Commit aacfc3fe authored by Stephen Morris's avatar Stephen Morris
Browse files

Merge branch 'master' into trac1593

parents 2ea7c1a1 65bbecec
382. [func] jelte
b10-auth now also experimentally supports statistics counters of
the rcode reponses it sends. The counters can be shown as
rcode.<code name>, where code name is the lowercase textual
representation of the rcode (e.g. "noerror", "formerr", etc.).
Same note applies as for opcodes, see changelog entry 364.
(Trac #1613, git e98da500d7b02e11347431a74f2efce5a7d622aa)
381. [bug] jinmei
b10-auth: honor the DNSSEC DO bit in the new query handler.
(Trac #1695, git 61f4da5053c6a79fbc162fb16f195cdf8f94df64)
380. [bug] jinmei
libdns++: miscellaneous bug fixes for the NSECPARAM RDATA
implementation, including incorrect handling for empty salt and
incorrect comparison logic.
(Trac #1638, git 966c129cc3c538841421f1e554167d33ef9bdf25)
379. [bug] jelte
Configuration commands in bindctl now check for list indices if
the 'identifier' argument points to a child element of a list
item. Previously, it was possible to 'get' non-existent values
by leaving out the index, e.g. "config show Auth/listen_on/port,
which should be config show Auth/listen_on[<index>]/port, since
Auth/listen_on is a list. The command without an index will now
show an error. It is still possible to show/set the entire list
("config show Auth/listen_on").
(Trac #1649, git 003ca8597c8d0eb558b1819dbee203fda346ba77)
378. [func] vorner
It is possible to start authoritative server or resolver in multiple
instances, to use more than one core. Configuration is described in
the guide.
(Trac #1596, git 17f7af0d8a42a0a67a2aade5bc269533efeb840a)
377. [bug] jinmei
libdns++: miscellaneous bug fixes for the NSEC and NSEC3 RDATA
implementation, including a crash in NSEC3::toText() for some RR
types, incorrect handling of empty NSEC3 salt, and incorrect
comparison logic in NSEC3::compare().
(Trac #1641, git 28ba8bd71ae4d100cb250fd8d99d80a17a6323a2)
376. [bug] jinmei, vorner
The new query handling module of b10-auth did not handle type DS
query correctly: It didn't look for it in the parent zone, and
......
......@@ -907,7 +907,7 @@ AC_PATH_PROGS(AWK, gawk awk)
AC_SUBST(AWK)
AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
[regenerate man pages [default=no]])], enable_man=yes, enable_man=no)
[regenerate man pages [default=no]])], enable_man=$enableval, enable_man=no)
AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno)
......
This diff is collapsed.
......@@ -913,7 +913,24 @@ address, but the usual ones don't." mean? -->
In short, you should think twice before disabling something here.
</para>
</note>
<para>
It is possible to start some components multiple times (currently
<command>b10-auth</command> and <command>b10-resolzer</command>).
You might want to do that to gain more performance (each one uses only
single core). Just put multiple entries under different names, like
this, with the same config:
<screen>&gt; <userinput>config add Boss/components b10-resolver-2</userinput>
&gt; <userinput>config set Boss/components/b10-resolver-2/special resolver</userinput>
&gt; <userinput>config set Boss/components/b10-resolver-2/kind needed</userinput>
&gt; <userinput>config commit</userinput></screen>
</para>
<para>
However, this is work in progress and the support is not yet complete.
For example, each resolver will have its own cache, each authoritative
server will keep its own copy of in-memory data and there could be
problems with locking the sqlite database, if used. The configuration
might be changed to something more convenient in future.
</para>
</section>
</chapter>
......
......@@ -97,7 +97,13 @@
{
"command_name": "shutdown",
"command_description": "Shut down authoritative DNS server",
"command_args": []
"command_args": [
{
"item_name": "pid",
"item_type": "integer",
"item_optional": true
}
]
},
{
"command_name": "sendstats",
......@@ -210,7 +216,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 8",
"item_description": "The number of total request counts whose opcode is8 (reserved)"
"item_description": "The number of total request counts whose opcode is 8 (reserved)"
},
{
"item_name": "opcode.reserved9",
......@@ -218,7 +224,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 9",
"item_description": "The number of total request counts whose opcode is9 (reserved)"
"item_description": "The number of total request counts whose opcode is 9 (reserved)"
},
{
"item_name": "opcode.reserved10",
......@@ -226,7 +232,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 10",
"item_description": "The number of total request counts whose opcode is10 (reserved)"
"item_description": "The number of total request counts whose opcode is 10 (reserved)"
},
{
"item_name": "opcode.reserved11",
......@@ -234,7 +240,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 11",
"item_description": "The number of total request counts whose opcode is11 (reserved)"
"item_description": "The number of total request counts whose opcode is 11 (reserved)"
},
{
"item_name": "opcode.reserved12",
......@@ -242,7 +248,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 12",
"item_description": "The number of total request counts whose opcode is12 (reserved)"
"item_description": "The number of total request counts whose opcode is 12 (reserved)"
},
{
"item_name": "opcode.reserved13",
......@@ -250,7 +256,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 13",
"item_description": "The number of total request counts whose opcode is13 (reserved)"
"item_description": "The number of total request counts whose opcode is 13 (reserved)"
},
{
"item_name": "opcode.reserved14",
......@@ -258,7 +264,7 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 14",
"item_description": "The number of total request counts whose opcode is14 (reserved)"
"item_description": "The number of total request counts whose opcode is 14 (reserved)"
},
{
"item_name": "opcode.reserved15",
......@@ -266,7 +272,143 @@
"item_optional": true,
"item_default": 0,
"item_title": "Received requests opcode 15",
"item_description": "The number of total request counts whose opcode is15 (reserved)"
"item_description": "The number of total request counts whose opcode is 15 (reserved)"
},
{
"item_name": "rcode.noerror",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent success response",
"item_description": "The number of total responses with rcode 0 (NOERROR)"
},
{
"item_name": "rcode.formerr",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'format error' response",
"item_description": "The number of total responses with rcode 1 (FORMERR)"
},
{
"item_name": "rcode.servfail",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'server failure' response",
"item_description": "The number of total responses with rcode 2 (SERVFAIL)"
},
{
"item_name": "rcode.nxdomain",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'name error' response",
"item_description": "The number of total responses with rcode 3 (NXDOMAIN)"
},
{
"item_name": "rcode.notimp",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'not implemented' response",
"item_description": "The number of total responses with rcode 4 (NOTIMP)"
},
{
"item_name": "rcode.refused",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'refused' response",
"item_description": "The number of total responses with rcode 5 (REFUSED)"
},
{
"item_name": "rcode.yxdomain",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'name unexpectedly exists' response",
"item_description": "The number of total responses with rcode 6 (YXDOMAIN)"
},
{
"item_name": "rcode.yxrrset",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'rrset unexpectedly exists' response",
"item_description": "The number of total responses with rcode 7 (YXRRSET)"
},
{
"item_name": "rcode.nxrrset",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'no such rrset' response",
"item_description": "The number of total responses with rcode 8 (NXRRSET)"
},
{
"item_name": "rcode.notauth",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'not authoritative' response",
"item_description": "The number of total responses with rcode 9 (NOTAUTH)"
},
{
"item_name": "rcode.notzone",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'name not in zone' response",
"item_description": "The number of total responses with rcode 10 (NOTZONE)"
},
{
"item_name": "rcode.reserved11",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent response with rcode 11",
"item_description": "The number of total responses with rcode 11 (reserved)"
},
{
"item_name": "rcode.reserved12",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent response with rcode 12",
"item_description": "The number of total responses with rcode 12 (reserved)"
},
{
"item_name": "rcode.reserved13",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent response with rcode 13",
"item_description": "The number of total responses with rcode 13 (reserved)"
},
{
"item_name": "rcode.reserved14",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent response with rcode 14",
"item_description": "The number of total responses with rcode 14 (reserved)"
},
{
"item_name": "rcode.reserved15",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent response with rcode 15",
"item_description": "The number of total responses with rcode 15 (reserved)"
},
{
"item_name": "rcode.badvers",
"item_type": "integer",
"item_optional": true,
"item_default": 0,
"item_title": "Sent 'EDNS version not implemented' response",
"item_description": "The number of total responses with rcode 16 (BADVERS)"
}
]
}
......
......@@ -29,6 +29,8 @@ namespace auth {
// Debug messages indicating normal startup are logged at this debug level.
const int DBG_AUTH_START = DBGLVL_START_SHUT;
// Debug messages upon shutdown
const int DBG_AUTH_SHUT = DBGLVL_START_SHUT;
// Debug level used to log setting information (such as configuration changes).
const int DBG_AUTH_OPS = DBGLVL_COMMAND;
......
......@@ -192,6 +192,10 @@ reason for the failure is included in the message.
Initialization of the authoritative server has completed successfully
and it is entering the main loop, waiting for queries to arrive.
% AUTH_SHUTDOWN asked to stop, doing so
This is a debug message indicating the server was asked to shut down and it is
complying to the request.
% AUTH_SQLITE3 nothing to do for loading sqlite3
This is a debug message indicating that the authoritative server has
found that the data source it is loading is an SQLite3 data source,
......
......@@ -128,6 +128,22 @@ public:
/// Bind the ModuleSpec object in config_session_ with
/// isc:config::ModuleSpec::validateStatistics.
void registerStatisticsValidator();
/// \brief Resume the server
///
/// This is a wrapper call for DNSServer::resume(done), if 'done' is true,
/// the Rcode set in the given Message is counted in the statistics
/// counter.
///
/// This method is expected to be called by processMessage()
///
/// \param server The DNSServer as passed to processMessage()
/// \param message The response as constructed by processMessage()
/// \param done If true, the Rcode from the given message is counted,
/// this value is then passed to server->resume(bool)
void resumeServer(isc::asiodns::DNSServer* server,
isc::dns::MessagePtr message,
bool done);
private:
std::string db_file_;
......@@ -409,13 +425,13 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
// Ignore all responses.
if (message->getHeaderFlag(Message::HEADERFLAG_QR)) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_RECEIVED);
server->resume(false);
impl_->resumeServer(server, message, false);
return;
}
} catch (const Exception& ex) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_HEADER_PARSE_FAIL)
.arg(ex.what());
server->resume(false);
impl_->resumeServer(server, message, false);
return;
}
......@@ -426,13 +442,13 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
.arg(error.getRcode().toText()).arg(error.what());
makeErrorMessage(message, buffer, error.getRcode());
server->resume(true);
impl_->resumeServer(server, message, true);
return;
} catch (const Exception& ex) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
.arg(ex.what());
makeErrorMessage(message, buffer, Rcode::SERVFAIL());
server->resume(true);
impl_->resumeServer(server, message, true);
return;
} // other exceptions will be handled at a higher layer.
......@@ -459,7 +475,7 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
if (tsig_error != TSIGError::NOERROR()) {
makeErrorMessage(message, buffer, tsig_error.toRcode(), tsig_context);
server->resume(true);
impl_->resumeServer(server, message, true);
return;
}
......@@ -492,7 +508,7 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
}
}
server->resume(send_answer);
impl_->resumeServer(server, message, send_answer);
}
bool
......@@ -526,7 +542,8 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, MessagePtr message,
if (memory_client_ && memory_client_class_ == question->getClass()) {
const RRType& qtype = question->getType();
const Name& qname = question->getName();
auth::Query(*memory_client_, qname, qtype, *message).process();
auth::Query(*memory_client_, qname, qtype, *message,
dnssec_ok).process();
} else {
datasrc::Query query(*message, cache_, dnssec_ok);
data_sources_.doQuery(query);
......@@ -754,6 +771,14 @@ AuthSrvImpl::setDbFile(ConstElementPtr config) {
return (answer);
}
void
AuthSrvImpl::resumeServer(DNSServer* server, MessagePtr message, bool done) {
if (done) {
counters_.inc(message->getRcode());
}
server->resume(done);
}
ConstElementPtr
AuthSrv::updateConfig(ConstElementPtr new_config) {
try {
......@@ -783,6 +808,11 @@ AuthSrv::getCounter(const Opcode opcode) const {
return (impl_->counters_.getCounter(opcode));
}
uint64_t
AuthSrv::getCounter(const Rcode rcode) const {
return (impl_->counters_.getCounter(rcode));
}
const AddressList&
AuthSrv::getListenAddresses() const {
return (impl_->listen_addresses_);
......
......@@ -344,6 +344,7 @@ public:
/// \param type Type of a counter to get the value of
///
/// \return the value of the counter.
uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
/// \brief Get the value of per Opcode counter in the Auth Counters.
......@@ -360,6 +361,20 @@ public:
/// \return the value of the counter.
uint64_t getCounter(const isc::dns::Opcode opcode) const;
/// \brief Get the value of per Rcode counter in the Auth Counters.
///
/// This function calls AuthCounters::getCounter(isc::dns::Rcode) and
/// returns its return value.
///
/// \note This is a tentative interface as an attempt of experimentally
/// supporting more statistics counters. This should eventually be more
/// generalized. In any case, this method is mainly for testing.
///
/// \throw None
/// \param rcode The rcode of the counter to get the value of
/// \return the value of the counter.
uint64_t getCounter(const isc::dns::Rcode rcode) const;
/**
* \brief Set and get the addresses we listen on.
*/
......
......@@ -12,24 +12,23 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <auth/command.h>
#include <auth/auth_log.h>
#include <auth/auth_srv.h>
#include <cc/data.h>
#include <datasrc/memory_datasrc.h>
#include <config/ccsession.h>
#include <exceptions/exceptions.h>
#include <dns/rrclass.h>
#include <cc/data.h>
#include <datasrc/memory_datasrc.h>
#include <string>
#include <config/ccsession.h>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <auth/auth_log.h>
#include <auth/auth_srv.h>
#include <auth/command.h>
#include <sys/types.h>
#include <unistd.h>
using boost::scoped_ptr;
using namespace isc::auth;
......@@ -104,10 +103,30 @@ public:
virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) = 0;
};
// Handle the "shutdown" command. No argument is assumed.
// Handle the "shutdown" command. An optional parameter "pid" is used to
// see if it is really for our instance.
class ShutdownCommand : public AuthCommand {
public:
virtual void exec(AuthSrv& server, isc::data::ConstElementPtr) {
virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
// Is the pid argument provided?
if (args && args->contains("pid")) {
// If it is, we check it is the same as our PID
// This might throw in case the type is not an int, but that's
// OK, as it'll get converted to an error on higher level.
const int pid(args->get("pid")->intValue());
const pid_t my_pid(getpid());
if (my_pid != pid) {
// It is not for us
//
// Note that this is completely expected situation, if
// there are multiple instances of the server running and
// another instance is being shut down, we get the message
// too, due to the multicast nature of our message bus.
return;
}
}
LOG_DEBUG(auth_logger, DBG_AUTH_SHUT, AUTH_SHUTDOWN);
server.stop();
}
};
......
......@@ -117,7 +117,7 @@ Query::addSOA(ZoneFinder& finder) {
// either an SERVFAIL response or just ignoring the query. We at least prevent
// a complete crash due to such broken behavior.
void
Query::addNXDOMAINProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
if (nsec->getRdataCount() == 0) {
isc_throw(BadNSEC, "NSEC for NXDOMAIN is empty");
}
......@@ -168,22 +168,79 @@ Query::addNXDOMAINProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
}
void
Query::addWildcardProof(ZoneFinder& finder) {
// The query name shouldn't exist in the zone if there were no wildcard
// substitution. Confirm that by specifying NO_WILDCARD. It should result
// in NXDOMAIN and an NSEC RR that proves it should be returned.
const ZoneFinder::FindResult fresult =
finder.find(qname_, RRType::NSEC(),
dnssec_opt_ | ZoneFinder::NO_WILDCARD);
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
isc_throw(BadNSEC, "Unexpected result for wildcard proof");
Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
// Firstly get the NSEC3 proves for Closest Encloser Proof
// See section 7.2.1 of RFC 5155.
// Since this is a Name Error case both closest and next proofs should
// be available (see addNXRRsetProof).
const ZoneFinder::FindNSEC3Result fresult1 = finder.findNSEC3(qname_,
true);
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<AbstractRRset>(
fresult1.closest_proof),
dnssec_);
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<AbstractRRset>(
fresult1.next_proof),
dnssec_);
// Next, construct the wildcard name at the closest encloser, i.e.,
// '*' followed by the closest encloser, and add NSEC3 for it.
const Name wildname(Name("*").concatenate(
qname_.split(qname_.getLabelCount() -
fresult1.closest_labels)));
const ZoneFinder::FindNSEC3Result fresult2 =
finder.findNSEC3(wildname, false);
if (fresult2.matched) {
isc_throw(BadNSEC3, "Matching NSEC3 found for nonexistent domain "
<< wildname);
}
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<AbstractRRset>(fresult.rrset),
boost::const_pointer_cast<AbstractRRset>(
fresult2.closest_proof),
dnssec_);
}
void
Query::addWildcardProof(ZoneFinder& finder,
const ZoneFinder::FindResult& db_result)
{
if (db_result.isNSECSigned()) {
// Case for RFC4035 Section 3.1.3.3.
//
// The query name shouldn't exist in the zone if there were no wildcard
// substitution. Confirm that by specifying NO_WILDCARD. It should
// result in NXDOMAIN and an NSEC RR that proves it should be returned.
const ZoneFinder::FindResult fresult =
finder.find(qname_, RRType::NSEC(),
dnssec_opt_ | ZoneFinder::NO_WILDCARD);
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
isc_throw(BadNSEC,
"Unexpected NSEC result for wildcard proof");
}
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<AbstractRRset>(
fresult.rrset),
dnssec_);
} else if (db_result.isNSEC3Signed()) {
// Case for RFC5155 Section 7.2.6.
//
// Note that the closest encloser must be the immediate ancestor
// of the matching wildcard, so NSEC3 for its next closer is what
// we are expected to provided per the RFC (if this assumption isn't
// met the zone is broken anyway).
const ZoneFinder::FindNSEC3Result NSEC3Result(
finder.findNSEC3(qname_, true));
// Note that at this point next_proof must not be NULL unless it's
// a run time collision (or zone/findNSEC3() is broken). The
// unexpected case will be caught in addRRset() and result in SERVFAIL.
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<AbstractRRset>(
NSEC3Result.next_proof), dnssec_);
}
}
void
Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
// There should be one NSEC RR which was found in the zone to prove
......@@ -214,10 +271,31 @@ Query::addDS(ZoneFinder& finder, const Name& dname) {