Commit 404aa060 authored by Evan Hunt's avatar Evan Hunt

Committed each-ds branch to trunk (still needing formal review; see

ticket #50 for full details)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@988 e5f2f494-b856-4b98-b285-d166d9295462
parent ec88f026
......@@ -139,6 +139,8 @@ AC_SUBST(GTEST_INCLUDES)
AC_SUBST(GTEST_LDFLAGS)
AC_SUBST(GTEST_LDADD)
PKG_CHECK_MODULES(SQLITE, sqlite3)
# Checks for library functions.
AC_CONFIG_FILES([Makefile
......
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/src/lib -I$(top_builddir)/src/lib/dns/cpp -I$(top_builddir)/include/dns/cpp -I$(top_builddir)/include -I$(top_srcdir)/ext
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/src/lib -I$(top_builddir)/src/lib/dns/cpp -I$(top_builddir)/include/dns/cpp -I$(top_builddir)/include -I$(top_srcdir)/ext $(SQLITE_CFLAGS)
pkglibexecdir = $(libexecdir)/@PACKAGE@
......@@ -8,11 +8,12 @@ pkglibexec_PROGRAMS = b10-auth
b10_auth_SOURCES = auth_srv.cc auth_srv.h
b10_auth_SOURCES += common.cc common.h
b10_auth_SOURCES += main.cc
b10_auth_LDADD = $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
b10_auth_LDADD += $(top_builddir)/src/lib/auth/cpp/.libs/libauth.a
b10_auth_LDADD = $(top_builddir)/src/lib/auth/cpp/.libs/libauth.a
b10_auth_LDADD += $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
b10_auth_LDADD += $(top_builddir)/src/lib/config/cpp/libcfgclient.a
b10_auth_LDADD += $(top_builddir)/src/lib/cc/cpp/libcc.a
b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a
b10_auth_LDADD += $(SQLITE_LIBS)
# TODO: config.h.in is wrong because doesn't honor pkgdatadir
# and can't use @datadir@ because doesn't expand default ${prefix}
......
......@@ -44,6 +44,7 @@
using namespace std;
using namespace isc::auth;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::data;
......@@ -68,6 +69,14 @@ AuthSrv::AuthSrv(int port) {
throw FatalError("could not bind socket");
sock = s;
// add static data source
data_src.addDataSrc(new StaticDataSrc);
// add SQL data source
Sqlite3DataSrc* sd = new Sqlite3DataSrc;
sd->init();
data_src.addDataSrc(sd);
}
void
......@@ -104,7 +113,7 @@ AuthSrv::processMessage() {
// do the DataSource call here
Query q = Query(msg, false);
data_src.runQuery(q);
data_src.doQuery(q);
OutputBuffer obuffer(4096);
MessageRenderer renderer(obuffer);
......
......@@ -19,11 +19,11 @@
#include <cc/data.h>
#include <auth/data_source_static.h>
#include <auth/data_source_sqlite3.h>
class AuthSrv {
public:
explicit AuthSrv(int port);
//~AuthSrv() {}
int getSocket() { return (sock); }
void processMessage();
void serve(std::string zone_name);
......@@ -31,8 +31,7 @@ public:
isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);
private:
// TODO: make this a MetaDataSrc, but that one is abstract...
isc::dns::StaticDataSrc data_src;
isc::auth::MetaDataSrc data_src;
int sock;
};
......
......@@ -50,7 +50,7 @@ import isc.cc
import isc
# This is the version that gets displayed to the user.
__version__ = "v20091030 (Paving the DNS Parking Lot)"
__version__ = "v20100225"
# Nothing at all to do with the 1990-12-10 article here:
# http://www.subgenius.com/subg-digest/v2/0056.html
......
......@@ -5,4 +5,21 @@ CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libauth.la
libauth_la_SOURCES = data_source.h data_source.cc
libauth_la_SOURCES += data_source_static.h data_source_static.cc
libauth_la_SOURCES += data_source_sqlite3.h data_source_sqlite3.cc
libauth_la_SOURCES += query.h query.cc
TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += unittest_util.h unittest_util.cc
run_unittests_SOURCES += unittest_ds.h unittest_ds.cc
run_unittests_SOURCES += datasrc_unittest.cc
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += .libs/libauth.a
run_unittests_LDADD += $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a
endif
noinst_PROGRAMS = $(TESTS)
- NXDOMAIN case must add NSEC/NSEC3 data when wantDnssec()
- DataSrc should implement a method findAddrRRsets() which queries
for A and AAAA records. at the high level this would be implemented
as two queries in serial; low level subclasses could override it with
a single query.
- change filenames so we don't have everything starting with "data_source_"?
- clean up SQL data source code
- store rdata in the database as binary blobs instead of text
This diff is collapsed.
......@@ -20,57 +20,101 @@
#include <boost/foreach.hpp>
#include <dns/name.h>
#include <dns/rrset.h>
#include <dns/rrsetlist.h>
#include <auth/query.h>
#include <iostream>
using namespace isc::dns;
namespace isc {
namespace dns {
enum DSResult {
SUCCESS,
NOT_IMPLEMENTED,
ERROR,
CNAME,
ZONE_NOT_FOUND,
NAME_NOT_FOUND,
TYPE_NOT_FOUND
};
namespace auth {
class DataSrc;
typedef std::vector<RRsetPtr> RRsetList;
class NameMatch;
class AbstractDataSrc {
public:
enum Result {
SUCCESS,
ERROR,
NOT_IMPLEMENTED
};
// These flags indicate conditions encountered while processing a query.
//
// REFERRAL: The node contains an NS record
// CNAME_FOUND: The node contains a CNAME record
// NAME_NOT_FOUND: The node does not exist in the data source.
// TYPE_NOT_FOUND: The node does not contain the requested RRType
// NO_SUCH_ZONE: The zone does not exist in this data source.
enum QueryResponseFlags {
REFERRAL = 0x01,
CNAME_FOUND = 0x02,
NAME_NOT_FOUND = 0x04,
TYPE_NOT_FOUND = 0x08,
NO_SUCH_ZONE = 0x10
};
virtual ~AbstractDataSrc() {};
// 'High-level' methods. These will be implemented by the
// general DataSrc class, but MAY be overwritten by subclasses.
virtual DSResult runQuery(Query query) = 0;
// Mandatory 'low-level' methods: These will NOT be implemented by
// the general DataSrc class; subclasses MUST implement them.
virtual DSResult findRRset(const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
RRsetList& sigs) const = 0;
// general DataSrc class, and SHOULD NOT be overwritten by subclasses.
virtual void doQuery(Query query) = 0;
virtual DSResult findRRset(const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target) const = 0;
// XXX: High-level methods to be implemented later:
// virtual void doUpdate(Update update) = 0;
// virtual void doXfr(Query query) = 0;
virtual const DataSrc* findClosestEnclosure(const Name& qname,
Name& container,
bool& found) const = 0;
// 'Medium-level' methods. This will be implemented by the general
// DataSrc class but MAY be overwritten by subclasses.
virtual void findClosestEnclosure(NameMatch& match) const = 0;
// Optional 'low-level' methods. These will have stub implementations
// in the general DataSrc class but MAY be overwritten by subclasses
virtual DSResult init() = 0;
virtual DSResult close() = 0;
virtual Result init() = 0;
virtual Result close() = 0;
// Mandatory 'low-level' methods: These will NOT be implemented by
// the general DataSrc class; subclasses MUST implement them.
virtual Result findRRset(const Query& q,
const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const = 0;
virtual Result findExactRRset(const Query& q,
const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const = 0;
// These will have dumb implementations in the general DataSrc
// class, and SHOULD be overwritten by subclasses.
virtual Result findAddrs(const Query& q,
const Name& qname,
const RRClass& qclass,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const = 0;
virtual Result findReferral(const Query& q,
const Name& qname,
const RRClass& qclass,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const = 0;
// This MUST be implemented by concrete data sources which support
// DNSSEC, but is optional for others (e.g., the static data source).
virtual Result findPreviousName(const Query& q,
const Name& qname,
Name& target,
Name* zone) const = 0;
//virtual const RRClass& getClass() const = 0;
//virtual const RRClass& setClass() const = 0;
};
// Base class for a DNS Data Source
......@@ -80,29 +124,111 @@ public:
DataSrc(const RRClass& c) : rrclass(c) {}
virtual ~DataSrc() {};
DSResult runQuery(Query q);
void doQuery(Query q);
virtual void findClosestEnclosure(NameMatch& match) const = 0;
virtual DSResult findRRset(const Name& qname,
const RRClass& getClass() const { return rrclass; }
void setClass(RRClass& c) { rrclass = c; }
void setClass(const RRClass& c) { rrclass = c; }
Result init() { return NOT_IMPLEMENTED; }
Result close() { return NOT_IMPLEMENTED; }
virtual Result findRRset(const Query& q,
const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const = 0;
virtual Result findExactRRset(const Query& q,
const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const = 0;
virtual Result findAddrs(const Query& q,
const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target,
RRsetList& sigs) const = 0;
uint32_t& flags,
Name* zone = NULL) const {
Result r;
bool a = false, aaaa = false;
flags = 0;
r = findExactRRset(q, qname, qclass, RRType::A(), target, flags, zone);
if (r == SUCCESS && flags == 0) {
a = true;
}
virtual DSResult findRRset(const Name& qname,
const RRClass& qclass,
const RRType& qtype,
RRsetList& target) const = 0;
flags = 0;
r = findExactRRset(q, qname, qclass, RRType::AAAA(), target,
flags, zone);
if (r == SUCCESS && flags == 0) {
aaaa = true;
}
virtual const DataSrc* findClosestEnclosure(const Name& qname,
Name& container,
bool& found) const = 0;
if (!a && !aaaa) {
flags = TYPE_NOT_FOUND;
} else {
flags = 0;
}
const RRClass& getClass() const { return rrclass; }
void setClass(RRClass& c) { rrclass = c; }
return (SUCCESS);
}
virtual Result findReferral(const Query& q,
const Name& qname,
const RRClass& qclass,
RRsetList& target,
uint32_t& flags,
Name* zone = NULL) const {
Result r;
bool ns = false, ds = false, dname = false;
flags = 0;
r = findExactRRset(q, qname, qclass, RRType::NS(), target, flags, zone);
if (r == SUCCESS && flags == 0) {
ns = true;
} else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
return (SUCCESS);
}
flags = 0;
r = findExactRRset(q, qname, qclass, RRType::DS(), target, flags, zone);
if (r == SUCCESS && flags == 0) {
ds = true;
} else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
return (SUCCESS);
}
flags = 0;
r = findExactRRset(q, qname, qclass, RRType::DNAME(), target,
flags, zone);
if (r == SUCCESS && flags == 0) {
dname = true;
} else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
return (SUCCESS);
}
DSResult init() { return NOT_IMPLEMENTED; }
DSResult close() { return NOT_IMPLEMENTED; }
if (!ns && !dname && !ds) {
flags = TYPE_NOT_FOUND;
} else {
flags = 0;
}
return (SUCCESS);
}
virtual Result findPreviousName(const Query& q,
const Name& qname,
Name& target,
Name* zone) const = 0;
private:
RRClass rrclass;
};
......@@ -119,33 +245,101 @@ public:
}
data_sources.push_back(ds);
};
}
const DataSrc* findClosestEnclosure(const Name& qname,
Name& container,
bool& found) const
{
const DataSrc* best = NULL;
void findClosestEnclosure(NameMatch& match) const {
BOOST_FOREACH (DataSrc* ds, data_sources) {
const DataSrc* source;
if (getClass() != RRClass::ANY() && ds->getClass() != getClass()) {
continue;
}
source = ds->findClosestEnclosure(qname, container, found);
if (source != NULL) {
best = source;
}
ds->findClosestEnclosure(match);
}
return (best);
};
}
// Actual queries for data should not be sent to a MetaDataSrc object,
// so we return NOT_IMPLEMENTED if we receive any.
//
// The proper way to use the MetaDataSrc is to run findClosestEnclosure()
// to get a pointer to the best concrete data source for the specified
// zone, then send all queries directly to that data source.
Result findRRset(const Query& q, const Name& qname,
const RRClass& qclass, const RRType& qtype,
RRsetList& target, uint32_t& flags,
Name* zone = NULL) const {
return (NOT_IMPLEMENTED);
}
Result findExactRRset(const Query& q, const Name& qname,
const RRClass& qclass, const RRType& qtype,
RRsetList& target, uint32_t& flags,
Name* zone = NULL) const {
return (NOT_IMPLEMENTED);
}
Result findAddrs(const Query& q,
const Name& qname, const RRClass& qclass,
RRsetList& target, uint32_t& flags,
Name* zone = NULL) const {
return (NOT_IMPLEMENTED);
}
Result findReferral(const Query& q,
const Name& qname, const RRClass& qclass,
RRsetList& target, uint32_t& flags,
Name* zone = NULL) const {
return (NOT_IMPLEMENTED);
}
virtual Result findPreviousName(const Query& q,
const Name& qname,
Name& target,
Name* zone) const {
return (NOT_IMPLEMENTED);
}
private:
std::vector<DataSrc*> data_sources;
};
class NameMatch {
public:
NameMatch(const Name& qname) :
closest_name_(NULL), best_source_(NULL), qname_(qname) {}
~NameMatch() {
delete closest_name_;
}
void update(const DataSrc& new_source, const Name& container) {
if (closest_name_ == NULL) {
closest_name_ = new Name(container);
best_source_ = &new_source;
return;
}
NameComparisonResult::NameRelation cmp =
container.compare(*closest_name_).getRelation();
if (cmp == NameComparisonResult::SUBDOMAIN) {
Name* newname = new Name(container);
delete closest_name_;
closest_name_ = newname;
best_source_ = &new_source;
}
}
const Name& qname() { return (qname_); }
const Name* closestName() { return (closest_name_); }
const DataSrc* bestDataSrc() { return (best_source_); }
private:
const Name* closest_name_;
const DataSrc* best_source_;
const Name& qname_;
};
}
}
......
#include "data_source_sqlite3.h"
#include <dns/rrttl.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rrset.h>
#include <dns/rrsetlist.h>
#include <iostream>
using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
namespace isc {
namespace auth {
//
// Prepare a statement. Can call release() or sqlite3_finalize()
// directly.
//
sqlite3_stmt* Sqlite3DataSrc::prepare(const char *statement) {
int rc;
sqlite3_stmt *prepared = NULL;
rc = sqlite3_prepare_v2(db, statement, -1, &prepared, NULL);
if (rc != SQLITE_OK) {
throw("could not prepare");
}
return (prepared);
}
//
// Release memory associated with a prepared query.
//
void Sqlite3DataSrc::release(sqlite3_stmt* prepared) {
sqlite3_finalize(prepared);
}
//
// Get the database schema version.
//
int Sqlite3DataSrc::getVersion(void) {
if (database_version == -1) {
loadVersion();
}
return (database_version);
}
//
// Find the exact zone match. Return -1 if not found, or the zone's
// ID if found. This will always be >= 0 if found.
//
int Sqlite3DataSrc::hasExactZone(const char *name) const {
int rc, i;
sqlite3_reset(q_zone);
rc = sqlite3_bind_text(q_zone, 1, name, -1, SQLITE_STATIC);
if (rc != SQLITE_OK) {
throw("Could not bind");
}
rc = sqlite3_step(q_zone);
if (rc == SQLITE_ROW) {
i = sqlite3_column_int(q_zone, 0);
} else {
i = -1;
}
sqlite3_reset(q_zone);
return (i);
}
int
Sqlite3DataSrc::
findRecords(const Name& name, const RRType& rdtype, RRsetList& target,
Name* zone, const Mode mode, uint32_t& flags) const
{
int rc;
const string s_name = name.toText();
const char *c_name = s_name.c_str();
const string s_rdtype = rdtype.toText();
const char *c_rdtype = s_rdtype.c_str();
sqlite3_stmt *query;