Commit a0a39d4b authored by haikuo zhang's avatar haikuo zhang

Merge branch 'master' into trac1680

parents a2a9e24d cb40afcb
394. [defect] jelte
b10-auth now catches any exceptions during response building; if any
datasource either throws an exception or causes an exception to be
thrown, the message processing code will now catch it, log a debug
message, and return a SERVFAIL response.
(Trac #1612, git b5740c6b3962a55e46325b3c8b14c9d64cf0d845)
393. [func] jelte
Introduced a new class LabelSequence in libdns++, which provides
lightweight accessor functionality to the Name class, for more
efficient comparison of parts of names.
(Trac #1602, git b33929ed5df7c8f482d095e96e667d4a03180c78)
392. [func]* jinmei
libdns++: revised the (Abstract)MessageRenderer class so that it
has a default internal buffer and the buffer can be temporarily
switched. The constructor interface was modified, and a new
method setBuffer() was added.
(Trac #1697, git 9cabc799f2bf9a3579dae7f1f5d5467c8bb1aa40)
391. [bug]* vorner
The long time unused configuration options of Xfrout "log_name",
"log_file", "log_severity", "log_version" and "log_max_bytes" were
removed, as they had no effect (Xfrout uses the global logging
framework). However, if you have them set, you need to remove
them from the configuration file or the configuration will be
rejected.
(Trac #1090, git ef1eba02e4cf550e48e7318702cff6d67c1ec82e)
bind10-devel-20120301 released on March 1, 2012
390. [bug] vorner
......@@ -55,7 +84,7 @@ bind10-devel-20120301 released on March 1, 2012
382. [func] jelte
b10-auth now also experimentally supports statistics counters of
the rcode reponses it sends. The counters can be shown as
the rcode responses 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.
......
......@@ -1019,7 +1019,7 @@ Unix domain sockets
<!-- TODO -->
<note>
<para>
The development prototype release only provides the
The development prototype release only provides
<command>bindctl</command> as a user interface to
<command>b10-cmdctl</command>.
Upcoming releases will provide another interactive command-line
......@@ -1210,7 +1210,7 @@ or accounts database -->
The port can be set by using the <option>--port</option> command line option.
The address to listen on can be set using the <option>--address</option> command
line argument.
Each HTTPS connection is stateless and timesout in 1200 seconds
Each HTTPS connection is stateless and times out in 1200 seconds
by default. This can be
redefined by using the <option>--idle-timeout</option> command line argument.
</para>
......@@ -1661,7 +1661,7 @@ Xfrout/transfer_acl[0] {"action": "ACCEPT"} any (default)</screen>
&gt; <userinput>config commit</userinput></screen>
<para>Both Xfrout and Auth will use the system wide keyring to check
TSIGs in the incomming messages and to sign responses.</para>
TSIGs in the incoming messages and to sign responses.</para>
<note><simpara>
The way to specify zone specific configuration (ACLs, etc) is
......@@ -2371,7 +2371,7 @@ eth0 fe80::21e:8cff:fe9b:7349
In the Logging module, you can specify the configuration
for zero or more loggers; any that are not specified will
take appropriate default values..
take appropriate default values.
</para>
......
......@@ -73,6 +73,10 @@ attempt to parse the header of a received DNS packet has failed. (The
reason for the failure is given in the message.) The server will drop the
packet.
% AUTH_INVALID_STATISTICS_DATA invalid specification of statistics data specified
An error was encountered when the authoritiative server specified
statistics data which is invalid for the auth specification file.
% AUTH_LOAD_TSIG loading TSIG keys
This is a debug message indicating that the authoritative server
has requested the keyring holding TSIG keys from the configuration
......@@ -92,6 +96,18 @@ discovered that the memory data source is disabled for the given class.
This is a debug message reporting that the authoritative server has
discovered that the memory data source is enabled for the given class.
% AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY
This debug message is logged by the authoritative server when it receives
a NOTIFY packet that contains zero or more than one question. (A valid
NOTIFY packet contains one question.) The server will return a FORMERR
error to the sender.
% AUTH_NOTIFY_RRTYPE invalid question RR type (%1) in incoming NOTIFY
This debug message is logged by the authoritative server when it receives
a NOTIFY packet that an RR type of something other than SOA in the
question section. (The RR type received is included in the message.) The
server will return a FORMERR error to the sender.
% AUTH_NO_STATS_SESSION session interface for statistics is not available
The authoritative server had no session with the statistics module at the
time it attempted to send it data: the attempt has been abandoned. This
......@@ -102,18 +118,6 @@ This is a debug message produced by the authoritative server when it receives
a NOTIFY packet but the XFRIN process is not running. The packet will be
dropped and nothing returned to the sender.
% AUTH_NOTIFY_RRTYPE invalid question RR type (%1) in incoming NOTIFY
This debug message is logged by the authoritative server when it receives
a NOTIFY packet that an RR type of something other than SOA in the
question section. (The RR type received is included in the message.) The
server will return a FORMERR error to the sender.
% AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY
This debug message is logged by the authoritative server when it receives
a NOTIFY packet that contains zero or more than one question. (A valid
NOTIFY packet contains one question.) The server will return a FORMERR
error to the sender.
% AUTH_PACKET_PARSE_ERROR unable to parse received DNS packet: %1
This is a debug message, generated by the authoritative server when an
attempt to parse a received DNS packet has failed due to something other
......@@ -154,6 +158,19 @@ a command from the statistics module to send it data. The 'sendstats'
command is handled differently to other commands, which is why the debug
message associated with it has its own code.
% AUTH_RESPONSE_FAILURE exception while building response to query: %1
This is a debug message, generated by the authoritative server when an
attempt to create a response to a received DNS packet has failed. The
reason for the failure is given in the log message. A SERVFAIL response
is sent back. The most likely cause of this is an error in the data
source implementation; it is either creating bad responses or raising
exceptions itself.
% AUTH_RESPONSE_FAILURE_UNKNOWN unknown exception while building response to query
This debug message is similar to AUTH_RESPONSE_FAILURE, but further
details about the error are unknown, because it was signaled by something
which is not an exception. This is definitely a bug.
% AUTH_RESPONSE_RECEIVED received response message, ignoring
This is a debug message, this is output if the authoritative server
receives a DNS packet with the QR bit set, i.e. a DNS response. The
......@@ -260,7 +277,3 @@ This is a debug message output during the processing of a NOTIFY
request. The zone manager component has been informed of the request,
but has returned an error response (which is included in the message). The
NOTIFY request will not be honored.
% AUTH_INVALID_STATISTICS_DATA invalid specification of statistics data specified
An error was encountered when the authoritiative server specified
statistics data which is invalid for the auth specification file.
......@@ -481,35 +481,43 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
return;
}
// update per opcode statistics counter. This can only be reliable after
// TSIG check succeeds.
impl_->counters_.inc(message->getOpcode());
bool send_answer = true;
if (message->getOpcode() == Opcode::NOTIFY()) {
send_answer = impl_->processNotify(io_message, message, buffer,
tsig_context);
} else if (message->getOpcode() != Opcode::QUERY()) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_UNSUPPORTED_OPCODE)
.arg(message->getOpcode().toText());
makeErrorMessage(message, buffer, Rcode::NOTIMP(), tsig_context);
} else if (message->getRRCount(Message::SECTION_QUESTION) != 1) {
makeErrorMessage(message, buffer, Rcode::FORMERR(), tsig_context);
} else {
ConstQuestionPtr question = *message->beginQuestion();
const RRType &qtype = question->getType();
if (qtype == RRType::AXFR()) {
send_answer = impl_->processXfrQuery(io_message, message, buffer,
tsig_context);
} else if (qtype == RRType::IXFR()) {
send_answer = impl_->processXfrQuery(io_message, message, buffer,
tsig_context);
try {
// update per opcode statistics counter. This can only be reliable
// after TSIG check succeeds.
impl_->counters_.inc(message->getOpcode());
if (message->getOpcode() == Opcode::NOTIFY()) {
send_answer = impl_->processNotify(io_message, message, buffer,
tsig_context);
} else if (message->getOpcode() != Opcode::QUERY()) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_UNSUPPORTED_OPCODE)
.arg(message->getOpcode().toText());
makeErrorMessage(message, buffer, Rcode::NOTIMP(), tsig_context);
} else if (message->getRRCount(Message::SECTION_QUESTION) != 1) {
makeErrorMessage(message, buffer, Rcode::FORMERR(), tsig_context);
} else {
send_answer = impl_->processNormalQuery(io_message, message,
buffer, tsig_context);
ConstQuestionPtr question = *message->beginQuestion();
const RRType &qtype = question->getType();
if (qtype == RRType::AXFR()) {
send_answer = impl_->processXfrQuery(io_message, message,
buffer, tsig_context);
} else if (qtype == RRType::IXFR()) {
send_answer = impl_->processXfrQuery(io_message, message,
buffer, tsig_context);
} else {
send_answer = impl_->processNormalQuery(io_message, message,
buffer, tsig_context);
}
}
} catch (const std::exception& ex) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE)
.arg(ex.what());
makeErrorMessage(message, buffer, Rcode::SERVFAIL());
} catch (...) {
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE_UNKNOWN);
makeErrorMessage(message, buffer, Rcode::SERVFAIL());
}
impl_->resumeServer(server, message, send_answer);
}
......
......@@ -2,12 +2,12 @@
.\" Title: b10-auth
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: February 28, 2012
.\" Date: March 1, 2012
.\" Manual: BIND10
.\" Source: BIND10
.\" Language: English
.\"
.TH "B10\-AUTH" "8" "February 28, 2012" "BIND10" "BIND10"
.TH "B10\-AUTH" "8" "March 1, 2012" "BIND10" "BIND10"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
......@@ -161,16 +161,18 @@ argument to select the process ID to stop\&. (Note that the BIND 10 boss process
.PP
The statistics data collected by the
\fBb10\-stats\fR
daemon include:
daemon for
\(lqAuth\(rq
include:
.PP
auth\&.queries\&.tcp
queries\&.tcp
.RS 4
Total count of queries received by the
\fBb10\-auth\fR
server over TCP since startup\&.
.RE
.PP
auth\&.queries\&.udp
queries\&.udp
.RS 4
Total count of queries received by the
\fBb10\-auth\fR
......
......@@ -20,7 +20,7 @@
<refentry>
<refentryinfo>
<date>February 28, 2012</date>
<date>March 1, 2012</date>
</refentryinfo>
<refmeta>
......@@ -201,20 +201,20 @@
<para>
The statistics data collected by the <command>b10-stats</command>
daemon include:
daemon for <quote>Auth</quote> include:
</para>
<variablelist>
<varlistentry>
<term>auth.queries.tcp</term>
<term>queries.tcp</term>
<listitem><simpara>Total count of queries received by the
<command>b10-auth</command> server over TCP since startup.
</simpara></listitem>
</varlistentry>
<varlistentry>
<term>auth.queries.udp</term>
<term>queries.udp</term>
<listitem><simpara>Total count of queries received by the
<command>b10-auth</command> server over UDP since startup.
</simpara></listitem>
......
......@@ -87,7 +87,11 @@ protected:
server.setXfrinSession(&notify_session);
server.setStatisticsSession(&statistics_session);
}
virtual void processMessage() {
// If processMessage has been called before, parse_message needs
// to be reset. If it hasn't, there's no harm in doing so
parse_message->clear(Message::PARSE);
server.processMessage(*io_message, parse_message, response_obuffer,
&dnsserv);
}
......@@ -120,6 +124,17 @@ protected:
}
}
}
// 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);
}
IOService ios_;
DNSService dnss_;
MockSession statistics_session;
......@@ -479,17 +494,17 @@ TEST_F(AuthSrvTest, AXFRSendFail) {
}
TEST_F(AuthSrvTest, AXFRDisconnectFail) {
// In our usage disconnect() shouldn't fail. So we'll see the exception
// should it be thrown.
// In our usage disconnect() shouldn't fail. But even if it does,
// it should not disrupt service (so processMessage should have caught it)
xfrout.disableSend();
xfrout.disableDisconnect();
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("example.com"), RRClass::IN(),
RRType::AXFR());
createRequestPacket(request_message, IPPROTO_TCP);
EXPECT_THROW(server.processMessage(*io_message, parse_message,
response_obuffer, &dnsserv),
XfroutError);
EXPECT_NO_THROW(server.processMessage(*io_message, parse_message,
response_obuffer, &dnsserv));
// Since the disconnect failed, we should still be 'connected'
EXPECT_TRUE(xfrout.isConnected());
// XXX: we need to re-enable disconnect. otherwise an exception would be
// thrown via the destructor of the server.
......@@ -537,17 +552,16 @@ TEST_F(AuthSrvTest, IXFRSendFail) {
}
TEST_F(AuthSrvTest, IXFRDisconnectFail) {
// In our usage disconnect() shouldn't fail. So we'll see the exception
// should it be thrown.
// In our usage disconnect() shouldn't fail, but even if it does,
// procesMessage() should catch it.
xfrout.disableSend();
xfrout.disableDisconnect();
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("example.com"), RRClass::IN(),
RRType::IXFR());
createRequestPacket(request_message, IPPROTO_TCP);
EXPECT_THROW(server.processMessage(*io_message, parse_message,
response_obuffer, &dnsserv),
XfroutError);
EXPECT_NO_THROW(server.processMessage(*io_message, parse_message,
response_obuffer, &dnsserv));
EXPECT_TRUE(xfrout.isConnected());
// XXX: we need to re-enable disconnect. otherwise an exception would be
// thrown via the destructor of the server.
......@@ -747,7 +761,8 @@ updateConfig(AuthSrv* server, const char* const config_data,
ConstElementPtr result = config_answer->get("result");
EXPECT_EQ(Element::list, result->getType());
EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue()) <<
"Bad result from updateConfig: " << result->str();
}
// Install a Sqlite3 data source with testing data.
......@@ -987,11 +1002,10 @@ getDummyUnknownSocket() {
return (socket);
}
// Submit unexpected type of query and check it throws isc::Unexpected
// Submit unexpected type of query and check it is ignored
TEST_F(AuthSrvTest, queryCounterUnexpected) {
// This code isn't exception safe, but we'd rather keep the code
// simpler and more readable as this is only for tests and if it throws
// the program would immediately terminate anyway.
// simpler and more readable as this is only for tests
// Create UDP query packet.
UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
......@@ -1007,9 +1021,7 @@ TEST_F(AuthSrvTest, queryCounterUnexpected) {
request_renderer.getLength(),
getDummyUnknownSocket(), *endpoint);
EXPECT_THROW(server.processMessage(*io_message, parse_message,
response_obuffer, &dnsserv),
isc::Unexpected);
EXPECT_FALSE(dnsserv.hasAnswer());
}
TEST_F(AuthSrvTest, stop) {
......@@ -1038,4 +1050,231 @@ TEST_F(AuthSrvTest, listenAddresses) {
"Released tokens");
}
//
// 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::ZoneFinder::FindResult
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 FindResult
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);
}
}
......@@ -2,12 +2,12 @@
.\" Title: bind10
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
.\" Date: February 28, 2012
.\" Date: March 1, 2012
.\" Manual: BIND10
.\" Source: BIND10
.\" Language: English
.\"
.TH "BIND10" "8" "February 28, 2012" "BIND10" "BIND10"
.TH "BIND10" "8" "March 1, 2012" "BIND10" "BIND10"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
......@@ -297,9 +297,11 @@ will exit\&.
.PP
The statistics data collected by the
\fBb10\-stats\fR
daemon include:
daemon for
\(lqBoss\(rq
include:
.PP
bind10\&.boot_time
boot_time
.RS 4
The date and time that the
\fBbind10\fR
......
......@@ -20,7 +20,7 @@
<refentry>
<refentryinfo>
<date>February 28, 2012</date>
<date>March 1, 2012</date>
</refentryinfo>
<refmeta>
......@@ -433,13 +433,13 @@ xfrin
<para>
The statistics data collected by the <command>b10-stats</command>
daemon include:
daemon for <quote>Boss</quote> include:
</para>
<variablelist>
<varlistentry>