Commit 4f7e1f46 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

sync with master

Merge branch 'master' into trac467

Conflicts:
	src/bin/auth/tests/auth_srv_unittest.cc
parents 229239d5 002ba326
144. [build] jinmei
Introduced a workaround for clang++ build on FreeBSD (and probably
some other OSes). If building BIND 10 fails with clang++ due to
a link error about "__dso_handle", try again from the configure
script with CXX_LIBTOOL_LDFLAGS=-L/usr/lib (the path actually
doesn't matter; the important part is the -L flag). This
workaround is not automatically enabled as it's difficult to
detect the need for it dynamically, and must be enabled via the
variable by hand. (Trac #474, git cfde436)
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
b10-auth: updated query benchmark so that it can test in memory
data source. Also fixed a bug that the output buffer isn't
......@@ -58,21 +72,21 @@
(Trac #202, svn r3967)
135. [func] each
Add b10-recurse. This is an example recursive server that
Add b10-resolver. This is an example recursive server that
currently does forwarding only and no caching.
(Trac #327, svn r3903)
134. [func] vorner
b10-recurse supports timeouts and retries in forwarder mode.
b10-resolver 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.
b10-resolver.
(Trac #393, r3602)
132. [func] vorner
The b10-recurse is configured through config manager.
The b10-resolver is configured through config manager.
It has "listen_on" and "forward_addresses" options.
(Trac #389, r3448)
......@@ -135,7 +149,7 @@ bind10-devel-20101201 released on December 01, 2010
122. [func] stephen
src/bin/bind10: Added configuration options to Boss to determine
whether to start the authoritative server, recursive server (or
both). A dummy recursor has been provided for test purposes.
both). A dummy program has been provided for test purposes.
(Trac #412, svn r3676)
121. [func] jinmei
......@@ -777,8 +791,10 @@ bind10-devel-20100421 released on April 21, 2010
bind10-devel-20100319 released on March 19, 2010
For complete code revision history, see http://bind10.isc.org/browser
Specific subversion changesets can be accessed at:
Specific git changesets can be accessed at:
http://bind10.isc.org/changeset/rrrr
Subversion changesets are not accessible any more. The subversion
revision numbers will be replaced with corresponding git revisions.
Trac tickets can be accessed at: https://bind10.isc.org/ticket/nnn
LEGEND
......
......@@ -15,7 +15,7 @@ five year plan are described here:
This release includes the bind10 master process, b10-msgq message
bus, b10-auth authoritative DNS server (with SQLite3 backend),
b10-recurse forwarding DNS server, b10-cmdctl remote control daemon,
b10-resolver forwarding DNS server, b10-cmdctl remote control daemon,
b10-cfgmgr configuration manager, b10-xfrin AXFR inbound service,
b10-xfrout outgoing AXFR service, b10-zonemgr secondary manager,
b10-stats statistics collection and reporting daemon, and a new
......@@ -193,6 +193,7 @@ config revert: Revert all changes that have not been committed
config commit: Commit all changes
config diff: Show the changes that have not been committed yet
EXAMPLE SESSION
~> bindctl
......
......@@ -9,7 +9,23 @@ AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CXX
# Libtool configuration
#
# On FreeBSD (and probably some others), clang++ does not meet an autoconf
# assumption in identifying libtool configuration regarding shared library:
# the configure script will execute "$CC -shared $CFLAGS -v -o" and expect
# the output contains -Lxxx or -Ryyy. This is the case for g++, but not for
# clang++, and, as a result, it will cause various errors in linking programs
# or running them with a shared object (such as some of our python scripts).
# To work around this problem we define a temporary variable
# "CXX_LIBTOOL_LDFLAGS". It's expected to be defined as, e.g, "-L/usr/lib"
# to temporarily fake the output so that it will be compatible with that of
# g++.
CFLAGS_SAVED=$CFLAGS
CFLAGS="$CFLAGS $CXX_LIBTOOL_LDFLAGS"
AC_PROG_LIBTOOL
CFLAGS=$CFLAGS_SAVED
# Use C++ language
AC_LANG([C++])
......@@ -577,8 +593,8 @@ AC_CONFIG_FILES([Makefile
src/bin/auth/Makefile
src/bin/auth/tests/Makefile
src/bin/auth/benchmarks/Makefile
src/bin/recurse/Makefile
src/bin/recurse/tests/Makefile
src/bin/resolver/Makefile
src/bin/resolver/tests/Makefile
src/bin/xfrin/Makefile
src/bin/xfrin/tests/Makefile
src/bin/xfrout/Makefile
......@@ -597,6 +613,8 @@ AC_CONFIG_FILES([Makefile
src/lib/Makefile
src/lib/asiolink/Makefile
src/lib/asiolink/tests/Makefile
src/lib/asiolink/internal/Makefile
src/lib/asiolink/internal/tests/Makefile
src/lib/bench/Makefile
src/lib/bench/example/Makefile
src/lib/bench/tests/Makefile
......@@ -650,8 +668,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.spec.pre
src/bin/recurse/spec_config.h.pre
src/bin/resolver/resolver.spec.pre
src/bin/resolver/spec_config.h.pre
src/bin/zonemgr/zonemgr.py
src/bin/zonemgr/zonemgr.spec.pre
src/bin/zonemgr/tests/zonemgr_test
......@@ -694,7 +712,7 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
chmod +x src/bin/xfrin/run_b10-xfrin.sh
chmod +x src/bin/xfrout/run_b10-xfrout.sh
chmod +x src/bin/recurse/run_b10-recurse.sh
chmod +x src/bin/resolver/run_b10-resolver.sh
chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
chmod +x src/bin/stats/tests/stats_test
chmod +x src/bin/stats/run_b10-stats.sh
......
SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout \
usermgr zonemgr stats tests recurse
usermgr zonemgr stats tests resolver
check-recursive: all-recursive
......@@ -194,7 +194,7 @@ public:
/// control commands and configuration updates.
void setConfigSession(isc::config::ModuleCCSession* config_session);
/// \brief Assign an ASIO IO Service queue to this Recursor object
/// \brief Assign an ASIO IO Service queue to this Resolver object
void setIOService(asiolink::IOService& ios) { io_service_ = &ios; }
/// \brief Return this object's ASIO IO Service queue
......
......@@ -12,8 +12,12 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <vector>
#include <boost/foreach.hpp>
#include <dns/message.h>
#include <dns/rcode.h>
#include <dns/rdataclass.h>
#include <datasrc/memory_datasrc.h>
......@@ -21,10 +25,65 @@
using namespace isc::dns;
using namespace isc::datasrc;
using namespace isc::dns::rdata;
namespace isc {
namespace auth {
void
Query::getAdditional(const Zone& zone, const RRset& rrset) const {
RdataIteratorPtr rdata_iterator(rrset.getRdataIterator());
for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
const Rdata& rdata(rdata_iterator->getCurrent());
if (rrset.getType() == RRType::NS()) {
// Need to perform the search in the "GLUE OK" mode.
const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
} else if (rrset.getType() == RRType::MX()) {
const generic::MX& mx(dynamic_cast<const generic::MX&>(rdata));
findAddrs(zone, mx.getMXName());
}
}
}
void
Query::findAddrs(const Zone& zone, const Name& qname,
const Zone::FindOptions options) const
{
// Out of zone name
NameComparisonResult result = zone.getOrigin().compare(qname);
if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
(result.getRelation() != NameComparisonResult::EQUAL))
return;
// Omit additional data which has already been provided in the answer
// section from the additional.
//
// All the address rrset with the owner name of qname have been inserted
// into ANSWER section.
if (qname_ == qname && qtype_ == RRType::ANY())
return;
// Find A rrset
if (qname_ != qname || qtype_ != RRType::A()) {
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
if (qname_ != qname || qtype_ != RRType::AAAA()) {
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
Query::putSOA(const Zone& zone) const {
Zone::FindResult soa_result(zone.find(zone.getOrigin(),
......@@ -43,6 +102,22 @@ Query::putSOA(const Zone& zone) const {
}
}
void
Query::getAuthAdditional(const Zone& zone) const {
// Fill in authority and addtional sections.
Zone::FindResult ns_result = zone.find(zone.getOrigin(), RRType::NS());
// zone origin name should have NS records
if (ns_result.code != Zone::SUCCESS) {
isc_throw(NoApexNS, "There's no apex NS records in zone " <<
zone.getOrigin().toText());
} else {
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<RRset>(ns_result.rrset));
// Handle additional for authority section
getAdditional(zone, *ns_result.rrset);
}
}
void
Query::process() const {
bool keep_doing = true;
......@@ -70,11 +145,25 @@ Query::process() const {
case Zone::SUCCESS:
response_.setRcode(Rcode::NOERROR());
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset));
// TODO : fill in authority and addtional sections.
boost::const_pointer_cast<RRset>(db_result.rrset));
// Handle additional for answer section
getAdditional(*result.zone, *db_result.rrset);
// If apex NS records haven't been provided in the answer
// section, insert apex NS records into the authority section
// and AAAA/A RRS of each of the NS RDATA into the additional
// section.
if (qname_ != result.zone->getOrigin() ||
(qtype_ != RRType::NS() && qtype_ != RRType::ANY()))
{
getAuthAdditional(*result.zone);
}
break;
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;
case Zone::NXDOMAIN:
// Just empty answer with SOA in authority section
......@@ -93,5 +182,6 @@ Query::process() const {
}
}
}
}
}
......@@ -15,17 +15,18 @@
*/
#include <exceptions/exceptions.h>
#include <datasrc/zone.h>
namespace isc {
namespace dns {
class Message;
class Name;
class RRType;
class RRset;
}
namespace datasrc {
class MemoryDataSrc;
class Zone;
}
namespace auth {
......@@ -63,6 +64,72 @@ namespace auth {
/// accidentally, and since it's considered a temporary development state,
/// we keep this name at the moment.
class Query {
private:
/// \brief 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;
/// \brief Look up additional data (i.e., address records for the names
/// included in NS or MX records).
///
/// Note: Any additional data which has already been provided in the
/// answer section (i.e., if the original query happend to be for the
/// address of the DNS server), it should be omitted from the additional.
///
/// 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;
/// \brief 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 \c 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;
/// \brief Look up \c Zone's NS and address records for the NS RDATA
/// (domain name) for authoritative answer.
///
/// On returning an authoritative answer, insert the \c Zone's NS into the
/// authority section and AAAA/A RRs of each of the NS RDATA into the
/// additional section.
///
/// <b>Notes to developer:</b>
///
/// We should omit address records which has already been provided in the
/// answer section from the additional.
///
/// For now, in order to optimize the additional section processing, we
/// include AAAA/A RRs under a zone cut in additional section. (BIND 9
/// excludes under-cut RRs; NSD include them.)
///
/// \param zone The \c Zone wherein the additional data to the query is to
/// be found.
void getAuthAdditional(const isc::datasrc::Zone& zone) const;
public:
/// Constructor from query parameters.
///
......@@ -130,19 +197,21 @@ public:
{}
};
/// \short Zone is missing its apex NS records.
///
/// We tried to add apex NS records into the authority section, but the
/// zone does not contain any.
struct NoApexNS: public BadZone {
NoApexNS(const char* file, size_t line, const char* what) :
BadZone(file, line, what)
{}
};
private:
const isc::datasrc::MemoryDataSrc& memory_datasrc_;
const isc::dns::Name& qname_;
const isc::dns::RRType& qtype_;
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;
};
}
......
......@@ -36,6 +36,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
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/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
......
......@@ -33,14 +33,17 @@
#include <auth/common.h>
#include <auth/statistics.h>
#include <testutils/srv_unittest.h>
#include <dns/tests/unittest_util.h>
#include <testutils/srv_test.h>
using namespace std;
using namespace isc::cc;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::data;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::testutils;
using isc::UnitTestUtil;
namespace {
......@@ -57,6 +60,10 @@ protected:
server.setXfrinSession(&notify_session);
server.setStatisticsSession(&statistics_session);
}
virtual void processMessage() {
server.processMessage(*io_message, parse_message, response_obuffer,
&dnsserv);
}
MockSession statistics_session;
MockXfroutClient xfrout;
AuthSrv server;
......@@ -161,48 +168,52 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
// Unsupported requests. Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
UNSUPPORTED_REQUEST_TEST;
unsupportedRequest();
}
// Simple API check
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.
TEST_F(AuthSrvTest, multiQuestion) {
MULTI_QUESTION_TEST;
multiQuestion();
}
// Incoming data doesn't even contain the complete header. Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
SHORT_MESSAGE_TEST;
shortMessage();
}
// Response messages. Must be silently dropped, whether it's a valid response
// or malformed or could otherwise cause a protocol error.
TEST_F(AuthSrvTest, response) {
RESPONSE_TEST;
response();
}
// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
SHORT_QUESTION_TEST;
shortQuestion();
}
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
SHORT_ANSWER_TEST;
shortAnswer();
}
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
EDNS_BADVERS_TEST;
ednsBadVers();
}
TEST_F(AuthSrvTest, AXFROverUDP) {
AXFR_OVER_UDP_TEST;
axfrOverUDP();
}
TEST_F(AuthSrvTest, AXFRSuccess) {
......
......@@ -17,6 +17,7 @@
#include <dns/rcode.h>
#include <dns/rrttl.h>
#include <dns/rrtype.h>
#include <dns/rdataclass.h>
#include <datasrc/memory_datasrc.h>
......@@ -36,19 +37,70 @@ RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
RRClass::IN(), RRType::SOA(),
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))));
RRsetPtr delegated_mx_a_rrset(RRsetPtr(new RRset(
Name("mx.delegation.example.com"), RRClass::IN(), RRType::A(),
RRTTL(3600))));
// This is a mock Zone class for testing.
// It is a derived class of Zone, and simply hardcode the results of find()
// return SUCCESS for "www.example.com",
// return NXDOMAIN for "nxdomain.example.com",
// return NXRRSET for "nxrrset.example.com",
// return CNAME for "cname.example.com",
// else return DNAME
// It is a derived class of Zone, and simply hardcodes the results of find()
// See the find() implementation if you want to know its content.
class MockZone : public Zone {
public:
MockZone(bool has_SOA = true) :
MockZone(bool has_SOA = true, bool has_apex_NS = true) :
origin_(Name("example.com")),
has_SOA_(has_SOA)
{}
has_SOA_(has_SOA),
has_apex_NS_(has_apex_NS),
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)))),
auth_ns_rrset(RRsetPtr(new RRset(Name("example.com"),
RRClass::IN(), RRType::NS(),
RRTTL(3600)))),
mx_cname_rrset_(new RRset(Name("cnamemailer.example.com"),
RRClass::IN(), RRType::CNAME(), RRTTL(3600))),
mx_rrset_(new RRset(Name("mx.example.com"), RRClass::IN(),
RRType::MX(), 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")));
auth_ns_rrset->addRdata(rdata::generic::NS(
Name("glue.ns.example.com")));
auth_ns_rrset->addRdata(rdata::generic::NS(
Name("noglue.example.com")));
auth_ns_rrset->addRdata(rdata::generic::NS(
Name("example.net")));
mx_rrset_->addRdata(isc::dns::rdata::generic::MX(10,
Name("www.example.com")));
mx_rrset_->addRdata(isc::dns::rdata::generic::MX(20,
Name("mailer.example.org")));
mx_rrset_->addRdata(isc::dns::rdata::generic::MX(30,
Name("mx.delegation.example.com")));
mx_cname_rrset_->addRdata(rdata::generic::CNAME(
Name("mx.example.com")));
}
virtual const isc::dns::Name& getOrigin() const;
virtual const isc::dns::RRClass& getClass() const;
......@@ -59,6 +111,12 @@ public:
private:
Name origin_;
bool has_SOA_;
bool has_apex_NS_;
RRsetPtr delegation_rrset;
RRsetPtr cname_rrset;
RRsetPtr auth_ns_rrset;
RRsetPtr mx_cname_rrset_;
RRsetPtr mx_rrset_;
};
const Name&
......@@ -72,22 +130,52 @@ MockZone::getClass() const {
}
Zone::FindResult
MockZone::find(const Name& name, const RRType& type, const FindOptions) const {
MockZone::find(const Name& name, const RRType& type,
const FindOptions options)