[svn] commit: r988 - in /trunk: ./ src/bin/auth/ src/bin/bind10/ src/lib/auth/cpp/ src/lib/auth/cpp/testdata/ src/lib/dns/cpp/ src/lib/dns/cpp/rdata/generic/ src/lib/dns/cpp/tests/ src/lib/dns/cpp/tests/testdata/
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Feb 26 06:32:44 UTC 2010
Author: each
Date: Fri Feb 26 06:32:44 2010
New Revision: 988
Log:
Committed each-ds branch to trunk (still needing formal review; see
ticket #50 for full details)
Added:
trunk/src/lib/auth/cpp/data_source_sqlite3.cc
trunk/src/lib/auth/cpp/data_source_sqlite3.h
trunk/src/lib/auth/cpp/datasrc_unittest.cc
trunk/src/lib/auth/cpp/run_unittests.cc
trunk/src/lib/auth/cpp/testdata/
trunk/src/lib/auth/cpp/testdata/q_cname
trunk/src/lib/auth/cpp/testdata/q_cname_ext
trunk/src/lib/auth/cpp/testdata/q_cname_int
trunk/src/lib/auth/cpp/testdata/q_dname
trunk/src/lib/auth/cpp/testdata/q_example_ns
trunk/src/lib/auth/cpp/testdata/q_example_ptr
trunk/src/lib/auth/cpp/testdata/q_glork
trunk/src/lib/auth/cpp/testdata/q_spork
trunk/src/lib/auth/cpp/testdata/q_sql1
trunk/src/lib/auth/cpp/testdata/q_subzone
trunk/src/lib/auth/cpp/testdata/q_subzone_ds
trunk/src/lib/auth/cpp/testdata/q_wild
trunk/src/lib/auth/cpp/testdata/q_www
trunk/src/lib/auth/cpp/unittest_ds.cc
trunk/src/lib/auth/cpp/unittest_ds.h
trunk/src/lib/auth/cpp/unittest_util.cc
trunk/src/lib/auth/cpp/unittest_util.h
trunk/src/lib/dns/cpp/dnstime.cc
trunk/src/lib/dns/cpp/dnstime.h
trunk/src/lib/dns/cpp/hex.cc
trunk/src/lib/dns/cpp/hex.h
trunk/src/lib/dns/cpp/rdata/generic/dname_39.cc
trunk/src/lib/dns/cpp/rdata/generic/dname_39.h
trunk/src/lib/dns/cpp/rdata/generic/dnskey_48.cc
trunk/src/lib/dns/cpp/rdata/generic/dnskey_48.h
trunk/src/lib/dns/cpp/rdata/generic/ds_43.cc
trunk/src/lib/dns/cpp/rdata/generic/ds_43.h
trunk/src/lib/dns/cpp/rdata/generic/nsec_47.cc
trunk/src/lib/dns/cpp/rdata/generic/nsec_47.h
trunk/src/lib/dns/cpp/tests/hex_unittest.cc
trunk/src/lib/dns/cpp/tests/testdata/rdata_dname_fromWire
trunk/src/lib/dns/cpp/tests/testdata/rdata_dnskey_fromWire
trunk/src/lib/dns/cpp/tests/testdata/rdata_ds_fromWire
trunk/src/lib/dns/cpp/tests/testdata/rdata_nsec_fromWire
Modified:
trunk/configure.ac
trunk/src/bin/auth/Makefile.am
trunk/src/bin/auth/auth_srv.cc
trunk/src/bin/auth/auth_srv.h
trunk/src/bin/bind10/bind10.py.in
trunk/src/lib/auth/cpp/Makefile.am
trunk/src/lib/auth/cpp/TODO
trunk/src/lib/auth/cpp/data_source.cc
trunk/src/lib/auth/cpp/data_source.h
trunk/src/lib/auth/cpp/data_source_static.cc
trunk/src/lib/auth/cpp/data_source_static.h
trunk/src/lib/auth/cpp/query.cc
trunk/src/lib/auth/cpp/query.h
trunk/src/lib/dns/cpp/Makefile.am
trunk/src/lib/dns/cpp/base64.cc
trunk/src/lib/dns/cpp/base64.h
trunk/src/lib/dns/cpp/message.cc
trunk/src/lib/dns/cpp/message.h
trunk/src/lib/dns/cpp/name.cc
trunk/src/lib/dns/cpp/name.h
trunk/src/lib/dns/cpp/rdata/generic/mx_15.cc
trunk/src/lib/dns/cpp/rdata/generic/mx_15.h
trunk/src/lib/dns/cpp/rdata/generic/rrsig_46.cc
trunk/src/lib/dns/cpp/rrclass-placeholder.h
trunk/src/lib/dns/cpp/rrset.cc
trunk/src/lib/dns/cpp/rrset.h
trunk/src/lib/dns/cpp/rrtype-placeholder.h
trunk/src/lib/dns/cpp/tests/Makefile.am
trunk/src/lib/dns/cpp/tests/base64_unittest.cc
trunk/src/lib/dns/cpp/tests/name_unittest.cc
trunk/src/lib/dns/cpp/tests/rdata_rrsig_unittest.cc
Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Fri Feb 26 06:32:44 2010
@@ -138,6 +138,8 @@
AC_SUBST(GTEST_INCLUDES)
AC_SUBST(GTEST_LDFLAGS)
AC_SUBST(GTEST_LDADD)
+
+PKG_CHECK_MODULES(SQLITE, sqlite3)
# Checks for library functions.
Modified: trunk/src/bin/auth/Makefile.am
==============================================================================
--- trunk/src/bin/auth/Makefile.am (original)
+++ trunk/src/bin/auth/Makefile.am Fri Feb 26 06:32:44 2010
@@ -1,4 +1,4 @@
-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 @@
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}
Modified: trunk/src/bin/auth/auth_srv.cc
==============================================================================
--- trunk/src/bin/auth/auth_srv.cc (original)
+++ trunk/src/bin/auth/auth_srv.cc Fri Feb 26 06:32:44 2010
@@ -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 @@
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 @@
// do the DataSource call here
Query q = Query(msg, false);
- data_src.runQuery(q);
+ data_src.doQuery(q);
OutputBuffer obuffer(4096);
MessageRenderer renderer(obuffer);
Modified: trunk/src/bin/auth/auth_srv.h
==============================================================================
--- trunk/src/bin/auth/auth_srv.h (original)
+++ trunk/src/bin/auth/auth_srv.h Fri Feb 26 06:32:44 2010
@@ -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 @@
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;
};
Modified: trunk/src/bin/bind10/bind10.py.in
==============================================================================
--- trunk/src/bin/bind10/bind10.py.in (original)
+++ trunk/src/bin/bind10/bind10.py.in Fri Feb 26 06:32:44 2010
@@ -50,7 +50,7 @@
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
Modified: trunk/src/lib/auth/cpp/Makefile.am
==============================================================================
--- trunk/src/lib/auth/cpp/Makefile.am (original)
+++ trunk/src/lib/auth/cpp/Makefile.am Fri Feb 26 06:32:44 2010
@@ -5,4 +5,21 @@
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)
Modified: trunk/src/lib/auth/cpp/TODO
==============================================================================
--- trunk/src/lib/auth/cpp/TODO (original)
+++ trunk/src/lib/auth/cpp/TODO Fri Feb 26 06:32:44 2010
@@ -1,5 +1,3 @@
-- 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
Modified: trunk/src/lib/auth/cpp/data_source.cc
==============================================================================
--- trunk/src/lib/auth/cpp/data_source.cc (original)
+++ trunk/src/lib/auth/cpp/data_source.cc Fri Feb 26 06:32:44 2010
@@ -1,119 +1,561 @@
+#include <iostream>
+#include <vector>
+
#include <dns/buffer.h>
+#include <dns/message.h>
#include <dns/name.h>
+#include <dns/rdataclass.h>
#include <dns/rrset.h>
-#include <dns/message.h>
+#include <dns/rrsetlist.h>
#include <cc/data.h>
#include "data_source.h"
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
namespace isc {
-namespace dns {
-
-DSResult
-DataSrc::runQuery(Query q) {
- DSResult result;
- Name container(".");
+namespace auth {
+
+// Add a task to the query task queue to look up additional data
+// (i.e., address records for the names included in NS or MX records)
+static void
+getAdditional(Query& q, RRsetPtr rrset) {
+ if (!q.wantAdditional()) {
+ return;
+ }
+
+ RdataIteratorPtr it = rrset->getRdataIterator();
+ for (it->first(); !it->isLast(); it->next()) {
+ const Rdata& rd(it->getCurrent());
+ QueryTask* t = NULL;
+ if (rrset->getType() == RRType::NS()) {
+ const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
+
+ t = new QueryTask(ns.getNSName(), q.qclass(),
+ Section::ADDITIONAL(),
+ QueryTask::GLUE_QUERY,
+ QueryTask::GETADDITIONAL);
+ } else if (rrset->getType() == RRType::MX()) {
+ const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
+ t = new QueryTask(mx.getMXName(), q.qclass(),
+ Section::ADDITIONAL(),
+ QueryTask::NOGLUE_QUERY,
+ QueryTask::GETADDITIONAL);
+ }
+ if (t != NULL) {
+ q.tasks().push(*t);
+ }
+ }
+}
+
+// Synthesize a CNAME answer, for the benefit of clients that don't
+// understand DNAME
+static void
+synthesizeCname(Query& q, QueryTask& task, RRsetPtr rrset, RRsetList& target) {
+ RdataIteratorPtr it;
+ it = rrset->getRdataIterator();
+
+ // More than one DNAME RR in the RRset is illegal, so we only have
+ // to process the first one.
+ it->first();
+ if (it->isLast()) {
+ return;
+ }
+
+ const Rdata& rd(it->getCurrent());
+ const generic::DNAME& dname = dynamic_cast<const generic::DNAME&>(rd);
+ const Name& dname_target(dname.getDname());
+
+ try {
+ int qnlen = task.qname.getLabelCount();
+ int dnlen = rrset->getName().getLabelCount();
+ const Name& prefix(task.qname.split(0, qnlen - dnlen));
+ const Name& newname(prefix.concatenate(dname_target));
+ RRsetPtr cname(new RRset(task.qname, task.qclass, RRType::CNAME(),
+ rrset->getTTL()));
+ cname->addRdata(generic::CNAME(newname));
+ cname->setTTL(rrset->getTTL());
+ target.addRRset(cname);
+ } catch (...) {}
+}
+
+// Add a task to the query task queue to look up the data pointed
+// to by a CNAME record
+static void
+chaseCname(Query& q, QueryTask& task, RRsetPtr rrset) {
+ RdataIteratorPtr it;
+ it = rrset->getRdataIterator();
+
+ // More than one CNAME RR in the RRset is illegal, so we only have
+ // to process the first one.
+ it->first();
+ if (it->isLast()) {
+ return;
+ }
+
+ const Rdata& rd(it->getCurrent());
+ const generic::CNAME& cname = dynamic_cast<const generic::CNAME&>(rd);
+ const Name& target(cname.getCname());
+
+ QueryTask* t = new QueryTask(target, task.qclass, task.qtype,
+ Section::ANSWER(), QueryTask::FOLLOWCNAME);
+ q.tasks().push(*t);
+}
+
+// Perform the query specified in a QueryTask object
+DataSrc::Result
+doQueryTask(const DataSrc* ds, Query& q, QueryTask& task, RRsetList& target) {
+ switch (task.op) {
+ case QueryTask::AUTH_QUERY:
+ return (ds->findRRset(q, task.qname, task.qclass, task.qtype,
+ target, task.flags, task.zone));
+
+ case QueryTask::SIMPLE_QUERY:
+ return (ds->findExactRRset(q, task.qname, task.qclass, task.qtype,
+ target, task.flags, task.zone));
+
+ case QueryTask::GLUE_QUERY:
+ case QueryTask::NOGLUE_QUERY:
+ return (ds->findAddrs(q, task.qname, task.qclass, target,
+ task.flags, task.zone));
+
+ case QueryTask::REF_QUERY:
+ return (ds->findReferral(q, task.qname, task.qclass, target,
+ task.flags, task.zone));
+ }
+
+ // Not reached
+ return (DataSrc::ERROR);
+}
+
+// Copy referral information into the authority section of a message
+static inline void
+copyAuth(Query& q, const RRsetList& auth) {
Message& m = q.message();
-
+ BOOST_FOREACH(RRsetPtr rrset, auth) {
+ if (rrset->getType() == RRType::DNAME()) {
+ continue;
+ }
+ m.addRRset(Section::AUTHORITY(), rrset, q.wantDnssec());
+ getAdditional(q, rrset);
+ }
+}
+
+// Query for referrals (i.e., NS/DS or DNAME) at a given name
+static inline bool
+refQuery(const Name& name, Query& q, QueryTask& task,
+ const DataSrc* ds, RRsetList& target) {
+ QueryTask t(name, q.qclass(), QueryTask::REF_QUERY);
+ t.zone = task.zone;
+
+ DataSrc::Result result = doQueryTask(ds, q, t, target);
+
+ // Lookup failed
+ if (result != DataSrc::SUCCESS) {
+ return (false);
+ }
+
+ // Referral bit is expected, so clear it when checking flags
+ if ((t.flags & ~DataSrc::REFERRAL) != 0) {
+ return (false);
+ }
+
+ return (true);
+}
+
+// Match downward, from the zone apex to the query name, looking for
+// referrals.
+static inline bool
+hasDelegation(const DataSrc* ds, Query& q, QueryTask& task) {
+ Message& m = q.message();
+ int nlen = task.qname.getLabelCount();
+ int diff = nlen - task.zone->getLabelCount();
+ if (diff > 1) {
+ bool found = false;
+ RRsetList ref;
+ for(int i = diff; i > 1; i--) {
+ Name sub(task.qname.split(i - 1, nlen - i));
+ if (refQuery(sub, q, task, ds, ref)) {
+ found = true;
+ break;
+ }
+ }
+
+ // Found a referral while getting additional data
+ // for something other than NS; we skip it.
+ if (found && task.op == QueryTask::NOGLUE_QUERY) {
+ return (true);
+ }
+
+ // Found a referral while getting answer data;
+ // send a delegation.
+ if (found) {
+ if (RRsetPtr r = ref[RRType::DNAME()]) {
+ RRsetList syn;
+ m.addRRset(Section::ANSWER(), r, q.wantDnssec());
+ m.setHeaderFlag(MessageFlag::AA());
+ synthesizeCname(q, task, r, syn);
+ if (syn.size() == 1) {
+ m.addRRset(Section::ANSWER(),
+ syn[RRType::CNAME()],
+ q.wantDnssec());
+ chaseCname(q, task, syn[RRType::CNAME()]);
+ return (true);
+ }
+ }
+
+ copyAuth(q, ref);
+ return (true);
+ }
+ }
+
+ // We appear to have authoritative data; set the header
+ // flag. (We may clear it later if we find a referral
+ // at the actual qname node.)
+ if (task.op == QueryTask::AUTH_QUERY &&
+ task.state == QueryTask::GETANSWER) {
+ m.setHeaderFlag(MessageFlag::AA());
+ }
+
+ return (false);
+}
+
+// Attempt a wildcard lookup
+static inline DataSrc::Result
+tryWildcard(Query& q, QueryTask& task, const DataSrc* ds, bool& found) {
+ Message& m = q.message();
+ DataSrc::Result result;
+ found = false;
+
+ if ((task.flags & DataSrc::NAME_NOT_FOUND) == 0 ||
+ (task.state != QueryTask::GETANSWER &&
+ task.state != QueryTask::FOLLOWCNAME)) {
+ return (DataSrc::SUCCESS);
+ }
+
+ int nlen = task.qname.getLabelCount();
+ int diff = nlen - task.zone->getLabelCount();
+ if (diff < 1) {
+ return (DataSrc::SUCCESS);
+ }
+
+ RRsetList wild;
+ Name star("*");
+ uint32_t rflags = 0;
+
+ for(int i = 1; i <= diff; i++) {
+ const Name& wname(star.concatenate(task.qname.split(i, nlen - i)));
+ QueryTask t(wname, task.qclass, task.qtype,
+ QueryTask::SIMPLE_QUERY);
+ t.zone = task.zone;
+ result = doQueryTask(ds, q, t, wild);
+ if (result == DataSrc::SUCCESS &&
+ (t.flags == 0 || (t.flags & DataSrc::CNAME_FOUND))) {
+ rflags = t.flags;
+ found = true;
+ break;
+ }
+ }
+
+ // A wildcard was found. Add the data to the answer
+ // section (but with the name changed to match the
+ // qname), and then continue as if this were a normal
+ // answer: if a CNAME, chase the target, otherwise
+ // add authority.
+ if (found) {
+ if (rflags & DataSrc::CNAME_FOUND) {
+ if (RRsetPtr rrset = wild[RRType::CNAME()]) {
+ rrset->setName(task.qname);
+ m.addRRset(Section::ANSWER(), rrset, q.wantDnssec());
+ chaseCname(q, task, rrset);
+ }
+ } else {
+ BOOST_FOREACH (RRsetPtr rrset, wild) {
+ rrset->setName(task.qname);
+ m.addRRset(Section::ANSWER(), rrset, q.wantDnssec());
+ }
+
+ RRsetList auth;
+ if (! refQuery(Name(*task.zone), q, task, ds, auth)) {
+ return (DataSrc::ERROR);
+ }
+
+ copyAuth(q, auth);
+ }
+ } else if (q.wantDnssec()) {
+ // No wildcard found; add an NSEC to prove it
+ RRsetList nsec;
+ QueryTask t = QueryTask(*task.zone, task.qclass, RRType::NSEC(),
+ QueryTask::SIMPLE_QUERY);
+ t.zone = task.zone;
+ result = doQueryTask(ds, q, t, nsec);
+ if (result != DataSrc::SUCCESS) {
+ return (DataSrc::ERROR);
+ }
+
+ if (t.flags == 0) {
+ m.addRRset(Section::AUTHORITY(), nsec[RRType::NSEC()], true);
+ }
+ }
+
+ return (DataSrc::SUCCESS);
+}
+
+//
+// doQuery: Processes a query.
+//
+void
+DataSrc::doQuery(Query q) {
+ Result result;
+ Message& m = q.message();
+ vector<RRsetPtr> additional;
+
+ // XXX: this is for testing purposes; it should be done when
+ // parsing the message for EDNS0 options
+ q.setWantDnssec(true);
+
+ m.clearHeaderFlag(MessageFlag::AA());
while (!q.tasks().empty()) {
- RRsetList data, sigs;
- bool found = false;
- QueryTaskPtr task = q.tasks().front();
+ RRsetList data;
+
+ QueryTask task = q.tasks().front();
q.tasks().pop();
- const DataSrc* ds = findClosestEnclosure(task->qname, container, found);
-
- if (ds == NULL) {
- result = ZONE_NOT_FOUND;
- } else if (q.wantDnssec()) {
- result = ds->findRRset(task->qname, task->qclass, task->qtype,
- data, sigs);
- // XXX validity check:
- // for now, there must only be exactly one RRset in data
- // and no more than one RRset in sigs. the rrtype of data
- // must match the sigtype of sigs, if any
+ // These task types should never be on the task queue.
+ if (task.op == QueryTask::SIMPLE_QUERY ||
+ task.op == QueryTask::REF_QUERY) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+
+ // Find the closest enclosing zone for which we are authoritative,
+ // and the concrete data source which is authoritative for it.
+ // (Note that RRtype DS queries need to go to the parent.)
+ Name search(".");
+ if (task.qtype == RRType::DS()) {
+ search = task.qname.split(1, task.qname.getLabelCount() - 1);
} else {
- result = ds->findRRset(task->qname, task->qclass, task->qtype,
- data);
- }
-
- switch (result) {
- case SUCCESS:
- // XXX: what if 'data' contains more than one RRset?
- m.addRRset(task->section, data[0]);
- if (q.wantDnssec() && sigs.size() == 1) {
- m.addRRset(task->section, sigs[0]);
- }
-
- if (q.status() == QUERY_FINISHING) {
- q.setStatus(QUERY_DONE);
- return (SUCCESS);
- }
-
- // if there are no more work items, add the authority section
- if (q.tasks().empty() && q.status() == QUERY_INCOMPLETE) {
- QueryTask *qt = new QueryTask(container, task->qclass,
- RRType::NS(),
- Section::AUTHORITY());
- q.tasks().push(QueryTaskPtr(qt));
- q.setStatus(QUERY_FINISHING);
- }
+ search = task.qname;
+ }
+
+ NameMatch match(search);
+ findClosestEnclosure(match);
+ const DataSrc* ds = match.bestDataSrc();
+ const Name* zone = match.closestName();
+
+ if (ds) {
+ task.zone = new Name(*zone);
+
+ // For these query task types, if there is more than
+ // one level between the zone name and qname, we need to
+ // check the intermediate nodes for referrals.
+ if ((task.op == QueryTask::AUTH_QUERY ||
+ task.op == QueryTask::NOGLUE_QUERY) &&
+ hasDelegation(ds, q, task)) {
continue;
-
- case CNAME:
- m.addRRset(task->section, data[0]);
- if (q.wantDnssec() && sigs.size() == 1) {
- m.addRRset(task->section, sigs[0]);
- }
-
- // if (data[0].getType() == RRType::CNAME()) {
- // // take apart the CNAME rdata and re-query HERE
- // }
+ }
+
+ result = doQueryTask(ds, q, task, data);
+ if (result != SUCCESS) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+
+ // Query found a referral; let's find out if that was expected--
+ // i.e., if an NS was at the zone apex, or if we were querying
+ // specifically for the NS, DS or DNAME record.
+ if ((task.flags & REFERRAL) &&
+ (zone->getLabelCount() == task.qname.getLabelCount() ||
+ task.qtype == RRType::NS() ||
+ task.qtype == RRType::DS() ||
+ task.qtype == RRType::DNAME())) {
+ task.flags &= ~REFERRAL;
+ }
+ } else {
+ task.flags = NO_SUCH_ZONE;
+ }
+
+ if (result == SUCCESS && task.flags == 0) {
+ bool have_ns = false, need_auth = false;
+ switch (task.state) {
+ case QueryTask::GETANSWER:
+ case QueryTask::FOLLOWCNAME:
+ BOOST_FOREACH(RRsetPtr rrset, data) {
+ m.addRRset(task.section, rrset, q.wantDnssec());
+ if (q.tasks().empty()) {
+ need_auth = true;
+ }
+ getAdditional(q, rrset);
+ if (rrset->getType() == RRType::NS()) {
+ have_ns = true;
+ }
+ }
+ q.setStatus(Query::ANSWERED);
+ if (need_auth && !have_ns) {
+ // Data found, no additional processing needed.
+ // Add the NS records for the enclosing zone to
+ // the authority section.
+ RRsetList auth;
+ if (! refQuery(Name(*zone), q, task, ds, auth)) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+
+ copyAuth(q, auth);
+ }
continue;
- case NAME_NOT_FOUND:
- q.setStatus(QUERY_NODATA);
- if (q.wantDnssec()) {
- result = ds->findRRset(container, task->qclass,
- RRType::SOA(), data, sigs);
- } else {
- result = ds->findRRset(container, task->qclass,
- RRType::SOA(), data);
- }
-
+ case QueryTask::GETADDITIONAL:
+ // Got additional data. Do not add it to the message
+ // yet; instead store it and copy it in at the end
+ // (this allow RRSIGs to be omitted if necessary).
+ BOOST_FOREACH(RRsetPtr rrset, data) {
+ if (q.status() == Query::ANSWERED &&
+ rrset->getName() == q.qname() &&
+ rrset->getType() == q.qtype()) {
+ continue;
+ }
+ additional.push_back(rrset);
+ }
+ continue;
+
+ default:
+ dns_throw (Unexpected, "unexpected query state");
+ }
+ } else if (result == ERROR || result == NOT_IMPLEMENTED) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ } else if (task.flags & CNAME_FOUND) {
+ // The qname node contains a CNAME. Add a new task to the
+ // queue to look up its target.
+ if (RRsetPtr rrset = data[RRType::CNAME()]) {
+ m.addRRset(task.section, rrset, q.wantDnssec());
+ chaseCname(q, task, rrset);
+ }
+ continue;
+ } else if (task.flags & REFERRAL) {
+ // The qname node contains an out-of-zone referral.
+ if (task.state == QueryTask::GETANSWER) {
+ RRsetList auth;
+ m.clearHeaderFlag(MessageFlag::AA());
+ if (! refQuery(task.qname, q, task, ds, auth)) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+ BOOST_FOREACH (RRsetPtr rrset, auth) {
+ if (rrset->getType() == RRType::DNAME()) {
+ continue;
+ }
+ if (rrset->getType() == RRType::DS() &&
+ task.qtype == RRType::DS()) {
+ m.addRRset(Section::ANSWER(), rrset, q.wantDnssec());
+ } else {
+ m.addRRset(Section::AUTHORITY(), rrset, q.wantDnssec());
+ }
+ getAdditional(q, rrset);
+ }
+ }
+ continue;
+ } else if (task.flags & NO_SUCH_ZONE) {
+ // No such zone. If we're chasing cnames or adding additional
+ // data, that's okay, but if doing an original query, return
+ // REFUSED.
+ if (task.state == QueryTask::GETANSWER) {
+ m.setRcode(Rcode::REFUSED());
+ return;
+ }
+ continue;
+ } else if (task.flags & (NAME_NOT_FOUND|TYPE_NOT_FOUND)) {
+ // No data found at this qname/qtype.
+ // If we were looking for answer data, not additional,
+ // and the name was not found, we need to find out whether
+ // there are any relevant wildcards.
+ bool wildcard_found = false;
+ result = tryWildcard(q, task, ds, wildcard_found);
+ if (result != SUCCESS) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+
+ if (wildcard_found) {
+ continue;
+ }
+
+ // If we've reached this point, there is definitely no answer.
+ // If we were chasing cnames or adding additional data, that's
+ // okay, but if we were doing an original query, reply with the
+ // SOA in the authority section. For NAME_NOT_FOUND, set
+ // NXDOMAIN, and also add the previous NSEC to the authority
+ // section. For TYPE_NOT_FOUND, do not set an error rcode,
+ // and send the current NSEC in the authority section.
+ Name nsecname(task.qname);
+ if (task.flags & NAME_NOT_FOUND) {
+ ds->findPreviousName(q, task.qname, nsecname, task.zone);
+ }
+
+ if (task.state == QueryTask::GETANSWER) {
+ if (task.flags & NAME_NOT_FOUND) {
+ m.setRcode(Rcode::NXDOMAIN());
+ }
+
+ RRsetList soa;
+ QueryTask t(Name(*zone), task.qclass, RRType::SOA(),
+ QueryTask::SIMPLE_QUERY);
+ t.zone = task.zone;
+ result = doQueryTask(ds, q, t, soa);
+ if (result != SUCCESS || t.flags != 0) {
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+
+ m.addRRset(Section::AUTHORITY(), soa[RRType::SOA()],
+ q.wantDnssec());
+ }
+
+ if (q.wantDnssec()) {
+ RRsetList nsec;
+ QueryTask t = QueryTask(nsecname, task.qclass, RRType::NSEC(),
+ QueryTask::SIMPLE_QUERY);
+ t.zone = task.zone;
+ result = doQueryTask(ds, q, t, nsec);
if (result != SUCCESS) {
m.setRcode(Rcode::SERVFAIL());
- return (ERROR);
- }
-
- m.setRcode(Rcode::NXDOMAIN());
- m.addRRset(Section::AUTHORITY(), data[0]);
- if (q.wantDnssec() && sigs.size() == 1) {
- m.addRRset(Section::AUTHORITY(), sigs[0]);
- }
- break;
-
- case TYPE_NOT_FOUND:
- m.setRcode(Rcode::NOERROR());
- q.setStatus(QUERY_NODATA);
- return (result);
-
- case ZONE_NOT_FOUND:
- m.setRcode(Rcode::REFUSED());
- q.setStatus(QUERY_NODATA);
- return (result);
-
- default:
- m.setRcode(Rcode::SERVFAIL());
- q.setStatus(QUERY_NODATA);
- return (result);
- }
- }
-
- return (result);
-};
-
-
-}
-}
+ return;
+ }
+
+ if (t.flags == 0) {
+ m.addRRset(Section::AUTHORITY(), nsec[RRType::NSEC()],
+ true);
+ }
+ }
+
+ return;
+ } else {
+ // Should never be reached!
+ m.setRcode(Rcode::SERVFAIL());
+ return;
+ }
+ }
+
+ // We're done, so now copy in the additional data:
+ // data first, then signatures. (If we run out of
+ // space, signatures in additional section are
+ // optional.)
+ BOOST_FOREACH(RRsetPtr rrset, additional) {
+ m.addRRset(Section::ADDITIONAL(), rrset, false);
+ }
+
+ if (q.wantDnssec()) {
+ BOOST_FOREACH(RRsetPtr rrset, additional) {
+ if (rrset->getRRsig()) {
+ m.addRRset(Section::ADDITIONAL(), rrset->getRRsig(), false);
+ }
+ }
+ }
+}
+
+}
+}
Modified: trunk/src/lib/auth/cpp/data_source.h
==============================================================================
--- trunk/src/lib/auth/cpp/data_source.h (original)
+++ trunk/src/lib/auth/cpp/data_source.h Fri Feb 26 06:32:44 2010
@@ -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;
+ // general DataSrc class, and SHOULD NOT be overwritten by subclasses.
+ virtual void doQuery(Query query) = 0;
+
+ // XXX: High-level methods to be implemented later:
+ // virtual void doUpdate(Update update) = 0;
+ // virtual void doXfr(Query query) = 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 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 DSResult findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target,
- RRsetList& sigs) const = 0;
-
- virtual DSResult findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target) const = 0;
-
- virtual const DataSrc* findClosestEnclosure(const Name& qname,
- Name& container,
- bool& found) 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 const RRClass& getClass() const = 0;
- //virtual const RRClass& setClass() const = 0;
+ 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;
+
};
// Base class for a DNS Data Source
@@ -80,29 +124,111 @@
DataSrc(const RRClass& c) : rrclass(c) {}
virtual ~DataSrc() {};
- DSResult runQuery(Query q);
-
- virtual DSResult findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target,
- RRsetList& sigs) const = 0;
-
- virtual DSResult findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target) const = 0;
-
- virtual const DataSrc* findClosestEnclosure(const Name& qname,
- Name& container,
- bool& found) const = 0;
+ void doQuery(Query q);
+
+ virtual void findClosestEnclosure(NameMatch& match) const = 0;
const RRClass& getClass() const { return rrclass; }
void setClass(RRClass& c) { rrclass = c; }
-
- DSResult init() { return NOT_IMPLEMENTED; }
- DSResult close() { return NOT_IMPLEMENTED; }
-
+ 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,
+ RRsetList& target,
+ 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;
+ }
+
+ flags = 0;
+ r = findExactRRset(q, qname, qclass, RRType::AAAA(), target,
+ flags, zone);
+ if (r == SUCCESS && flags == 0) {
+ aaaa = true;
+ }
+
+ if (!a && !aaaa) {
+ flags = TYPE_NOT_FOUND;
+ } else {
+ flags = 0;
+ }
+
+ 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);
+ }
+
+ 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 @@
}
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;
- }
- }
-
- return (best);
- };
+ ds->findClosestEnclosure(match);
+ }
+ }
+
+ // 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_;
+};
+
}
}
Modified: trunk/src/lib/auth/cpp/data_source_static.cc
==============================================================================
--- trunk/src/lib/auth/cpp/data_source_static.cc (original)
+++ trunk/src/lib/auth/cpp/data_source_static.cc Fri Feb 26 06:32:44 2010
@@ -1,4 +1,18 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+// $Id$
#include "data_source_static.h"
@@ -12,14 +26,18 @@
#include <iostream>
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
namespace isc {
-namespace dns {
-
-using namespace isc::dns::rdata;
+namespace auth {
StaticDataSrc::StaticDataSrc() : authors_name("authors.bind"),
version_name("version.bind")
{
+ setClass(RRClass::CH());
+
authors = RRsetPtr(new RRset(authors_name, RRClass::CH(),
RRType::TXT(), RRTTL(0)));
authors->addRdata(generic::TXT("Evan Hunt"));
@@ -47,88 +65,65 @@
version_ns->addRdata(generic::NS(version_name));
}
-const DataSrc*
-StaticDataSrc::findClosestEnclosure(const Name& qname, Name& container, bool& found) const {
- NameComparisonResult::NameRelation version_cmp =
- qname.compare(version_name).getRelation();
+void
+StaticDataSrc::findClosestEnclosure(NameMatch& match) const {
+ const Name& qname = match.qname();
+ NameComparisonResult::NameRelation cmp;
- if (version_cmp == NameComparisonResult::EQUAL ||
- version_cmp == NameComparisonResult::SUBDOMAIN) {
- NameComparisonResult::NameRelation sub_cmp =
- version_name.compare(container).getRelation();
-
- if (sub_cmp == NameComparisonResult::SUBDOMAIN) {
- container = authors_name;
- found = true;
- return this;
- } else if (!found && sub_cmp == NameComparisonResult::EQUAL) {
- found = true;
- return this;
- } else {
- return NULL;
- }
+ cmp = qname.compare(version_name).getRelation();
+ if (cmp == NameComparisonResult::EQUAL ||
+ cmp == NameComparisonResult::SUBDOMAIN) {
+ match.update(*this, version_name);
+ return;
}
- NameComparisonResult::NameRelation authors_cmp =
- qname.compare(authors_name).getRelation();
+ cmp = qname.compare(authors_name).getRelation();
+ if (cmp == NameComparisonResult::EQUAL ||
+ cmp == NameComparisonResult::SUBDOMAIN) {
+ match.update(*this, authors_name);
+ return;
+ }
+}
- if (authors_cmp == NameComparisonResult::EQUAL ||
- authors_cmp == NameComparisonResult::SUBDOMAIN) {
- NameComparisonResult::NameRelation sub_cmp =
- authors_name.compare(container).getRelation();
-
- if (sub_cmp == NameComparisonResult::SUBDOMAIN) {
- container = authors_name;
- found = true;
- return this;
- } else if (!found && sub_cmp == NameComparisonResult::EQUAL) {
- found = true;
- return this;
- } else {
- return NULL;
- }
+DataSrc::Result
+StaticDataSrc::findRRset(const Query& q,
+ const Name& qname,
+ const RRClass& qclass,
+ const RRType& qtype,
+ RRsetList& target,
+ uint32_t& flags,
+ Name* zone) const
+{
+ flags = 0;
+ if (qclass != getClass()) {
+ return (ERROR);
}
- return NULL;
-}
+ bool any = (qtype == RRType::ANY());
-DSResult
-StaticDataSrc::findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target) const
-{
- if (qname == version_name &&
- qclass == version->getClass() && qtype == version->getType()) {
- target.push_back(version);
- return SUCCESS;
- } else if (qname == version_name &&
- qclass == version_ns->getClass() &&
- qtype == version_ns->getType()) {
- target.push_back(version_ns);
- return SUCCESS;
- } else if (qname == authors_name &&
- qclass == authors->getClass() && qtype == authors->getType()) {
- target.push_back(authors);
- return SUCCESS;
- } else if (qname == authors_name &&
- qclass == authors_ns->getClass() &&
- qtype == authors_ns->getType()) {
- target.push_back(authors_ns);
- return SUCCESS;
+ if (qname == version_name) {
+ if (qtype == RRType::TXT() || any) {
+ target.addRRset(version);
+ } else if (qtype == RRType::NS()) {
+ target.addRRset(version_ns);
+ } else {
+ flags = TYPE_NOT_FOUND;
+ }
+ } else if (qname == authors_name) {
+ if (qtype == RRType::TXT() || any) {
+ target.addRRset(authors);
+ return (SUCCESS);
+ } else if (qtype == RRType::NS()) {
+ target.addRRset(authors_ns);
+ return (SUCCESS);
+ } else {
+ flags = TYPE_NOT_FOUND;
+ }
+ } else {
+ flags = NAME_NOT_FOUND;
}
- // XXX: this is not 100% correct.
- // We should also support the nodata/noerror case.
- return NAME_NOT_FOUND;
-}
-DSResult
-StaticDataSrc::findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target, RRsetList& sigs) const
-{
- return findRRset(qname, qclass, qtype, target);
+ return (SUCCESS);
}
}
Modified: trunk/src/lib/auth/cpp/data_source_static.h
==============================================================================
--- trunk/src/lib/auth/cpp/data_source_static.h (original)
+++ trunk/src/lib/auth/cpp/data_source_static.h Fri Feb 26 06:32:44 2010
@@ -27,30 +27,46 @@
#include "data_source.h"
+using namespace isc::dns;
+
namespace isc {
-namespace dns {
+namespace auth {
class StaticDataSrc : public DataSrc {
public:
StaticDataSrc();
- ~StaticDataSrc() {};
+ ~StaticDataSrc() {}
- const DataSrc* findClosestEnclosure(const Name& qname,
- Name& container,
- bool& found) const;
+ void findClosestEnclosure(NameMatch& match) const;
- DSResult findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target, RRsetList& sigs) const;
+ Result findRRset(const Query& q,
+ const Name& qname,
+ const RRClass& qclass,
+ const RRType& qtype,
+ RRsetList& target,
+ uint32_t& flags,
+ Name* zone = NULL) const;
- DSResult findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target) const;
+ Result findExactRRset(const Query& q,
+ const Name& qname,
+ const RRClass& qclass,
+ const RRType& qtype,
+ RRsetList& target,
+ uint32_t& flags,
+ Name* zone = NULL) const
+ {
+ return (findRRset(q, qname, qclass, qtype, target, flags, zone));
+ }
- DSResult init() { return SUCCESS; };
- DSResult close() { return SUCCESS; } ;
+ Result findPreviousName(const Query& q,
+ const Name& qname,
+ Name& target,
+ Name* zone) const {
+ return (NOT_IMPLEMENTED);
+ }
+
+ Result init() { return (SUCCESS); }
+ Result close() { return (SUCCESS); }
private:
const Name authors_name;
Modified: trunk/src/lib/auth/cpp/query.cc
==============================================================================
--- trunk/src/lib/auth/cpp/query.cc (original)
+++ trunk/src/lib/auth/cpp/query.cc Fri Feb 26 06:32:44 2010
@@ -24,20 +24,10 @@
#include "query.h"
namespace isc {
-namespace dns {
+namespace auth {
-QueryTask::QueryTask(const Name& n, const RRClass& c,
- const RRType& t, const Section& s) :
- qname(n), qclass(c), qtype(t), section(s)
-{
- // Empty constructor. It is defined outside the class statement
- // because otherwise the linker will be confused.
-}
-
-QueryTask::~QueryTask() {
- // Empty destructor. It is defined outside the class statement
- // because otherwise the linker will be confused.
-}
+// Destructor defined here to avoid confusing the linker
+QueryTask::~QueryTask() {}
}
}
Modified: trunk/src/lib/auth/cpp/query.h
==============================================================================
--- trunk/src/lib/auth/cpp/query.h (original)
+++ trunk/src/lib/auth/cpp/query.h Fri Feb 26 06:32:44 2010
@@ -26,40 +26,152 @@
#include <dns/rrclass.h>
#include <dns/rrtype.h>
+using namespace isc::dns;
+
namespace isc {
-namespace dns {
-
-enum QueryStatus {
- QUERY_INCOMPLETE,
- QUERY_FINISHING,
- QUERY_DONE,
- QUERY_NODATA
-};
-
-///
-/// \brief exception to throw if a DNS Message is malformed
-///
-class MalformedMessage : public Exception {
-public:
- MalformedMessage(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
+namespace auth {
// An individual task to be carried out by the query logic
class QueryTask {
public:
- QueryTask(const Name& n, const RRClass& c,
- const RRType& t, const Section& s);
- virtual ~QueryTask();
-
+ // XXX: Members are currently public, but should probably be
+ // moved to private and wrapped in get() functions later.
+
+ // The standard query tuple: qname/qclass/qtype.
+ // Note that qtype is ignored in the GLUE_QUERY/NOGLUE_QUERY case.
const Name& qname;
const RRClass& qclass;
const RRType& qtype;
+
+ // Optional: name for the containing zone, if known.
+ // This is particularly needed when looking up data in a
+ // zone other than the closest enclosure (such as getting
+ // DS queries from a parent zone on a server which serves
+ // both parent and child).
+ Name* zone;
+
+ // The section of the reply into which the data should be
+ // written after it has been fetched from the data source.
const Section& section;
+
+ // The op field indicates the operation to be carried out by
+ // this query task:
+ //
+ // - SIMPLE_QUERY: look for a match for qname/qclass/qtype
+ // in local data (regardless of whether it is above or below
+ // a zone cut).
+ //
+ // - AUTH_QUERY: look for a match for qname/qclass/qtype, or
+ // for qname/qclass/CNAME, or for a referral.
+ //
+ // - GLUE_QUERY: look for matches with qname/qclass/A
+ // OR qname/class/AAAA in local data, regardless of
+ // authority, for use in glue. (This can be implemented
+ // as two successive SIMPLE_QUERY tasks, but might be
+ // optimized by the concrete data source implementation
+ // by turning it into a single database lookup.)
+ //
+ // - NOGLUE_QUERY: same as GLUE_QUERY except that answers
+ // are rejected if they are below a zone cut.
+ //
+ // - REF_QUERY: look for matches for qname/qclass/NS,
+ // qname/qclass/DS, and qname/qclass/DNAME. Used
+ // to search for a zone cut.
+
+ const enum Op {
+ SIMPLE_QUERY,
+ AUTH_QUERY,
+ GLUE_QUERY,
+ NOGLUE_QUERY,
+ REF_QUERY,
+ } op;
+
+ // The state field indicates the state of the query; it controls
+ // the next step after processing each query task.
+ //
+ // - GETANSWER: We are looking for the answer to a primary query.
+ // (The qname of the task should exactly match the qname of the
+ // query.) If we have no match, the query has failed.
+ //
+ // - GETADDITIONAL: We are filling in additional data, either
+ // as a result of finding NS or MX records via a GETANSWER
+ // query task, or as a result of finding NS records when
+ // getting authority-section data.
+ //
+ // - FOLLOWCNAME: We are looking for the target of a CNAME RR that
+ // was found via a previous GETANSWER query task. If we have no
+ // match, the query is still successful.
+ //
+ // (NOTE: It is only necessary to set a task state when pushing
+ // tasks onto the query task queue, which in turn is only necessary
+ // when it's uncertain which data source will be authoritative for the
+ // data. That's why there is no GETAUTHORITY task state; when
+ // processing an answer, either positive or negative, the authoritative
+ // data source will already have been discovered, and can be queried
+ // directly.)
+
+ enum State {
+ GETANSWER,
+ GETADDITIONAL,
+ FOLLOWCNAME
+ } state;
+
+ // Response flags to indicate conditions encountered while
+ // processing this task.
+ uint32_t flags;
+
+ // Constructors
+ QueryTask(const Name& n, const RRClass& c,
+ const RRType& t, const Section& sect) :
+ qname(n), qclass(c), qtype(t), zone(NULL),
+ section(sect), op(AUTH_QUERY), state(GETANSWER), flags(0) {}
+ QueryTask(const Name& n, const RRClass& c,
+ const RRType& t, const Section& sect, const Op o) :
+ qname(n), qclass(c), qtype(t), zone(NULL),
+ section(sect), op(o), state(GETANSWER), flags(0) {}
+ QueryTask(const Name& n, const RRClass& c,
+ const RRType& t, const Section& sect, const State st) :
+ qname(n), qclass(c), qtype(t), zone(NULL),
+ section(sect), op(AUTH_QUERY), state(st), flags(0) {}
+ QueryTask(const Name& n, const RRClass& c,
+ const RRType& t, const Section& sect,
+ const Op o, const State st) :
+ qname(n), qclass(c), qtype(t), zone(NULL),
+ section(sect), op(o), state(st), flags(0) {}
+
+ // These are special constructors for particular query task types,
+ // to simplify the code.
+ //
+ // A simple query doesn't need to specify section or state.
+ QueryTask(const Name& n, const RRClass& c, const RRType& t, const Op o) :
+ qname(n), qclass(c), qtype(t), zone(NULL),
+ section(Section::ANSWER()), op(o), state(GETANSWER), flags(0) {
+ if (op != SIMPLE_QUERY) {
+ throw "invalid constructor for this task operation";
+ }
+ }
+ // A referral query doesn't need to specify section, state, or type.
+ QueryTask(const Name& n, const RRClass& c, const Op o) :
+ qname(n), qclass(c), qtype(RRType::ANY()), zone(NULL),
+ section(Section::ANSWER()), op(o), state(GETANSWER), flags(0) {
+ if (op != REF_QUERY) {
+ throw "invalid constructor for this task operation";
+ }
+ }
+ // A glue (or noglue) query doesn't need to specify type.
+ QueryTask(const Name& n, const RRClass& c,
+ const Section& sect, const Op o, const State st) :
+ qname(n), qclass(c), qtype(RRType::ANY()), zone(NULL),
+ section(sect), op(o), state(st), flags(0) {
+ if (op != GLUE_QUERY && op != NOGLUE_QUERY) {
+ throw "invalid constructor for this task operation";
+ }
+ }
+
+ virtual ~QueryTask();
};
-typedef boost::shared_ptr<QueryTask> QueryTaskPtr;
-typedef std::queue<QueryTaskPtr> QueryTaskQueue;
+typedef std::queue<QueryTask> QueryTaskQueue;
class Query;
typedef boost::shared_ptr<Query> QueryPtr;
@@ -67,25 +179,31 @@
// Data Source query
class Query {
public:
+ // The state of a query: pending or answered.
+ enum Status {
+ PENDING,
+ ANSWERED
+ };
+
+ // Query constructor
Query(Message& m, bool dnssec) {
message_ = &m;
want_additional = true;
want_dnssec = dnssec;
- status_ = QUERY_INCOMPLETE;
+ status_ = PENDING;
// Check message formatting
- QuestionIterator qid = message_->beginQuestion();
- qid++;
- if (qid != message_->endQuestion())
- dns_throw(MalformedMessage, "too many questions");
-
- // Populate the query tasks queue with the initial question
+ if (message_->getRRCount(Section::QUESTION()) != 1) {
+ dns_throw(Unexpected, "malformed message: too many questions");
+ }
+
+ // Populate the query task queue with the initial question
QuestionPtr query = *message_->beginQuestion();
qname_ = &query->getName();
qclass_ = &query->getClass();
qtype_ = &query->getType();
- querytasks.push(QueryTaskPtr(new QueryTask(*qname_, *qclass_,
- *qtype_, Section::ANSWER())));
+ querytasks.push(QueryTask(*qname_, *qclass_, *qtype_,
+ Section::ANSWER()));
};
virtual ~Query() {}
@@ -108,13 +226,12 @@
Message& message() { return *message_; }
QueryTaskQueue& tasks() { return querytasks; }
- QueryStatus status() { return status_; }
- void setStatus(QueryStatus s) { status_ = s; }
-
-protected:
- QueryStatus status_;
+ Status status() { return status_; }
+ void setStatus(Status s) { status_ = s; }
private:
+ Status status_;
+
const Name* qname_;
const RRClass* qclass_;
const RRType* qtype_;
Modified: trunk/src/lib/dns/cpp/Makefile.am
==============================================================================
--- trunk/src/lib/dns/cpp/Makefile.am (original)
+++ trunk/src/lib/dns/cpp/Makefile.am Fri Feb 26 06:32:44 2010
@@ -19,6 +19,8 @@
libdns_la_SOURCES += question.h question.cc
libdns_la_SOURCES += message.h message.cc
libdns_la_SOURCES += base64.h base64.cc
+libdns_la_SOURCES += dnstime.h dnstime.cc
+libdns_la_SOURCES += hex.h hex.cc
rrclass.h: rrclass-placeholder.h
rrtype.h: rrtype-placeholder.h
Modified: trunk/src/lib/dns/cpp/base64.cc
==============================================================================
--- trunk/src/lib/dns/cpp/base64.cc (original)
+++ trunk/src/lib/dns/cpp/base64.cc Fri Feb 26 06:32:44 2010
@@ -14,6 +14,7 @@
// $Id$
+#include <stdint.h>
#include <cassert>
#include <iterator>
#include <string>
@@ -34,13 +35,12 @@
namespace {
const char BASE64_PADDING_CHAR = '=';
-const char BINARY_ZERO_CODE = 0;
-
-typedef
-class BinaryNormalizer : public iterator<input_iterator_tag, char> {
+const uint8_t BINARY_ZERO_CODE = 0;
+
+class BinaryNormalizer : public iterator<input_iterator_tag, uint8_t> {
public:
- BinaryNormalizer(const vector<char>::const_iterator& base,
- const vector<char>::const_iterator& base_end) :
+ BinaryNormalizer(const vector<uint8_t>::const_iterator& base,
+ const vector<uint8_t>::const_iterator& base_end) :
base_(base), base_end_(base_end), in_pad_(false)
{}
BinaryNormalizer& operator++()
@@ -53,7 +53,7 @@
}
return (*this);
}
- const char& operator*() const {
+ const uint8_t& operator*() const {
if (in_pad_) {
return (BINARY_ZERO_CODE);
} else {
@@ -65,17 +65,17 @@
return (base_ == other.base_);
}
private:
- vector<char>::const_iterator base_;
- const vector<char>::const_iterator base_end_;
+ vector<uint8_t>::const_iterator base_;
+ const vector<uint8_t>::const_iterator base_end_;
bool in_pad_;
};
-typedef
+typedef
base64_from_binary<transform_width<BinaryNormalizer, 6, 8> > base64_encoder;
} // end of anonymous namespace
string
-encodeBase64(const vector<char>& binary)
+encodeBase64(const vector<uint8_t>& binary)
{
// calculate the resulting length. it's the smallest multiple of 4
// equal to or larger than 4/3 * original data length.
@@ -138,7 +138,7 @@
} // end of anonymous namespace
void
-decodeBase64(const string& base64, vector<char>& result)
+decodeBase64(const string& base64, vector<uint8_t>& result)
{
// enumerate the number of trailing padding characters (=), ignoring
// white spaces. since base64_from_binary doesn't accept padding,
@@ -173,7 +173,7 @@
// Confirm the original base64 text is the canonical encoding of the
// data.
assert(result.size() >= padlen);
- vector<char>::const_reverse_iterator rit = result.rbegin();
+ vector<uint8_t>::const_reverse_iterator rit = result.rbegin();
for (int i = 0; i < padlen; ++i, ++rit) {
if (*rit != 0) {
dns_throw(BadBase64String, "Non 0 bits included in padding");
Modified: trunk/src/lib/dns/cpp/base64.h
==============================================================================
--- trunk/src/lib/dns/cpp/base64.h (original)
+++ trunk/src/lib/dns/cpp/base64.h Fri Feb 26 06:32:44 2010
@@ -17,6 +17,7 @@
#ifndef __BASE64_H
#define __BASE64_H 1
+#include <stdint.h>
#include <string>
#include <vector>
@@ -41,8 +42,8 @@
isc::Exception(file, line, what) {}
};
-std::string encodeBase64(const std::vector<char>& binary);
-void decodeBase64(const std::string& base64, std::vector<char>& result);
+std::string encodeBase64(const std::vector<uint8_t>& binary);
+void decodeBase64(const std::string& base64, std::vector<uint8_t>& result);
}
}
Modified: trunk/src/lib/dns/cpp/message.cc
==============================================================================
--- trunk/src/lib/dns/cpp/message.cc (original)
+++ trunk/src/lib/dns/cpp/message.cc Fri Feb 26 06:32:44 2010
@@ -216,6 +216,12 @@
impl_->flags_ |= flag.getBit();
}
+void
+Message::clearHeaderFlag(const MessageFlag& flag)
+{
+ impl_->flags_ &= ~flag.getBit();
+}
+
qid_t
Message::getQid() const
{
@@ -259,11 +265,17 @@
}
void
-Message::addRRset(const Section& section, RRsetPtr rrset)
+Message::addRRset(const Section& section, RRsetPtr rrset, bool sign)
{
// Note: should check duplicate (TBD)
impl_->rrsets_[sectionCodeToId(section)].push_back(rrset);
impl_->counts_[section.getCode()] += rrset->getRdataCount();
+
+ RRsetPtr sp = rrset->getRRsig();
+ if (sign && sp) {
+ impl_->rrsets_[sectionCodeToId(section)].push_back(sp);
+ impl_->counts_[section.getCode()] += sp->getRdataCount();
+ }
}
void
Modified: trunk/src/lib/dns/cpp/message.h
==============================================================================
--- trunk/src/lib/dns/cpp/message.h (original)
+++ trunk/src/lib/dns/cpp/message.h Fri Feb 26 06:32:44 2010
@@ -478,6 +478,7 @@
public:
bool getHeaderFlag(const MessageFlag& flag) const;
void setHeaderFlag(const MessageFlag& flag);
+ void clearHeaderFlag(const MessageFlag& flag);
qid_t getQid() const;
void setQid(qid_t qid);
const Rcode& getRcode() const;
@@ -502,7 +503,7 @@
void addQuestion(QuestionPtr question);
void addQuestion(const Question& question);
void removeQuestion(QuestionPtr question);
- void addRRset(const Section& section, RRsetPtr rrset);
+ void addRRset(const Section& section, RRsetPtr rrset, bool sign = false);
void removeRRset(const Section& section, RRsetPtr rrset);
// notyet:
//void addRR(const Section& section, const RR& rr);
@@ -528,6 +529,11 @@
static const rcode_t RCODE_NXDOMAIN = 3;
static const rcode_t RCODE_NOTIMP = 4;
static const rcode_t RCODE_REFUSED = 5;
+ static const rcode_t RCODE_YXDOMAIN = 6;
+ static const rcode_t RCODE_YXRRSET = 7;
+ static const rcode_t RCODE_NXRRSET = 8;
+ static const rcode_t RCODE_NOTAUTH = 9;
+ static const rcode_t RCODE_NOTZONE = 10;
// ...more to follow
static const opcode_t OPCODE_QUERY = 0;
Modified: trunk/src/lib/dns/cpp/name.cc
==============================================================================
--- trunk/src/lib/dns/cpp/name.cc (original)
+++ trunk/src/lib/dns/cpp/name.cc Fri Feb 26 06:32:44 2010
@@ -18,6 +18,8 @@
#include <cassert>
#include <iterator>
#include <functional>
+#include <vector>
+#include <iostream>
#include <algorithm>
@@ -606,6 +608,36 @@
}
Name
+Name::reverse() const
+{
+ Name retname;
+ //
+ // Set up offsets: The size of the string and number of labels will
+ // be the same in as in the original.
+ //
+ retname.offsets_.reserve(labelcount_);
+ retname.ndata_.reserve(length_);
+
+ // Copy the original name, label by label, from tail to head.
+ vector<unsigned char>::const_reverse_iterator rit0 = offsets_.rbegin();
+ vector<unsigned char>::const_reverse_iterator rit1 = rit0 + 1;
+ string::const_iterator n0 = ndata_.begin();
+ retname.offsets_.push_back(0);
+ while (rit1 != offsets_.rend()) {
+ retname.ndata_.append(n0 + *rit1, n0 + *rit0);
+ retname.offsets_.push_back(retname.ndata_.size());
+ ++rit0;
+ ++rit1;
+ }
+ retname.ndata_.push_back(0);
+
+ retname.labelcount_ = labelcount_;
+ retname.length_ = length_;
+
+ return (retname);
+}
+
+Name
Name::split(unsigned int first, unsigned int n) const
{
if (n == 0 || first + n > labelcount_) {
Modified: trunk/src/lib/dns/cpp/name.h
==============================================================================
--- trunk/src/lib/dns/cpp/name.h (original)
+++ trunk/src/lib/dns/cpp/name.h Fri Feb 26 06:32:44 2010
@@ -513,6 +513,14 @@
/// labels including and following the <code>first</code> label.
Name split(unsigned int first, unsigned int n) const;
+ /// \brief Reverse the labels of a name
+ ///
+ /// This method reverses the labels of a name. For example, if
+ /// \c this is "www.example.com.", this method will return
+ /// "com.example.www." (This is useful because DNSSEC sort order
+ /// is equivalent to a lexical sort of label-reversed names.)
+ Name reverse() const;
+
/// \brief Concatenate two names.
///
/// This method appends \c suffix to \c this Name. The trailing dot of
Modified: trunk/src/lib/dns/cpp/rdata/generic/mx_15.cc
==============================================================================
--- trunk/src/lib/dns/cpp/rdata/generic/mx_15.cc (original)
+++ trunk/src/lib/dns/cpp/rdata/generic/mx_15.cc Fri Feb 26 06:32:44 2010
@@ -38,10 +38,21 @@
// check consistency.
}
-MX::MX(const std::string& mxstr) :
+MX::MX(const std::string& mx_str) :
preference_(0), mxname_(".")
{
- dns_throw(InvalidRdataText, "Not implemented yet");
+ istringstream iss(mx_str);
+ uint16_t pref;
+ string mxname;
+
+ iss >> pref >> mxname;
+
+ if (iss.bad() || iss.fail() || !iss.eof()) {
+ dns_throw(InvalidRdataText, "Invalid MX text format");
+ }
+
+ preference_ = pref;
+ mxname_ = Name(mxname);
}
MX::MX(uint16_t preference, const Name& mxname) :
@@ -86,5 +97,17 @@
return (compareNames(mxname_, other_mx.mxname_));
}
+const Name&
+MX::getMXName() const
+{
+ return (mxname_);
+}
+
+const uint16_t
+MX::getMXPref() const
+{
+ return (preference_);
+}
+
// END_RDATA_NAMESPACE
// END_ISC_NAMESPACE
Modified: trunk/src/lib/dns/cpp/rdata/generic/mx_15.h
==============================================================================
--- trunk/src/lib/dns/cpp/rdata/generic/mx_15.h (original)
+++ trunk/src/lib/dns/cpp/rdata/generic/mx_15.h Fri Feb 26 06:32:44 2010
@@ -36,6 +36,12 @@
explicit MX(uint16_t preference, const Name& mxname);
+ ///
+ /// Specialized methods
+ ///
+ const Name& getMXName() const;
+ const uint16_t getMXPref() const;
+
private:
/// Note: this is a prototype version; we may reconsider
/// this representation later.
Modified: trunk/src/lib/dns/cpp/rdata/generic/rrsig_46.cc
==============================================================================
--- trunk/src/lib/dns/cpp/rdata/generic/rrsig_46.cc (original)
+++ trunk/src/lib/dns/cpp/rdata/generic/rrsig_46.cc Fri Feb 26 06:32:44 2010
@@ -15,11 +15,14 @@
// $Id$
#include <string>
+#include <iomanip>
+#include <iostream>
#include <sstream>
#include <vector>
#include "base64.h"
#include "buffer.h"
+#include "dnstime.h"
#include "messagerenderer.h"
#include "name.h"
#include "rrtype.h"
@@ -28,51 +31,25 @@
#include "rdataclass.h"
#include <boost/lexical_cast.hpp>
+#include <stdio.h>
+#include <time.h>
+
using namespace std;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
-
-namespace {
-inline uint32_t
-convertDNSSECTime(const string time_txt)
-{
- istringstream iss(time_txt);
-
- uint32_t timeval;
- iss >> timeval;
-
- // right now, we don't support the YYYYMMDDHHmmSS format for
- // expire/inception
- if (iss.bad() || iss.fail() || !iss.eof()) {
- dns_throw(InvalidRdataText, "Invalid RRSIG Time format");
- }
-
- return (timeval);
-}
-}
struct RRSIGImpl {
// straightforward representation of RRSIG RDATA fields
RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels,
uint32_t originalttl, uint32_t timeexpire, uint32_t timeinception,
uint16_t keyid, const Name& signer,
- const vector<char>& signature) :
+ const vector<uint8_t>& signature) :
covered_(covered), algorithm_(algorithm), labels_(labels),
originalttl_(originalttl), timeexpire_(timeexpire),
timeinception_(timeinception), keyid_(keyid), signer_(signer),
signature_(signature)
{}
- RRSIGImpl(const RRType& covered, uint8_t algorithm, uint8_t labels,
- uint32_t originalttl, uint32_t timeexpire, uint32_t timeinception,
- uint16_t keyid, const Name& signer,
- const string& signature_txt) :
- covered_(covered), algorithm_(algorithm), labels_(labels),
- originalttl_(originalttl), timeexpire_(timeexpire),
- timeinception_(timeinception), keyid_(keyid), signer_(signer)
- {
- decodeBase64(signature_txt, signature_);
- }
const RRType covered_;
uint8_t algorithm_;
@@ -82,7 +59,7 @@
uint32_t timeinception_;
uint16_t keyid_;
const Name signer_;
- vector<char> signature_;
+ const vector<uint8_t> signature_;
};
RRSIG::RRSIG(const string& rrsig_str) :
@@ -108,12 +85,15 @@
dns_throw(InvalidRdataText, "RRSIG labels out of range");
}
- uint32_t timeexpire = convertDNSSECTime(expire_txt);
- uint32_t timeinception = convertDNSSECTime(inception_txt);
+ uint32_t timeexpire = DNSSECTimeFromText(expire_txt);
+ uint32_t timeinception = DNSSECTimeFromText(inception_txt);
+
+ vector<uint8_t> signature;
+ decodeBase64(signaturebuf.str(), signature);
impl_ = new RRSIGImpl(RRType(covered_txt), algorithm, labels,
originalttl, timeexpire, timeinception, keyid,
- Name(signer_txt), signaturebuf.str());
+ Name(signer_txt), signature);
}
RRSIG::RRSIG(InputBuffer& buffer, size_t rdata_len)
@@ -146,12 +126,16 @@
string
RRSIG::toText() const
{
+ string expire, inception;
+ DNSSECTimeToText(impl_->timeexpire_, expire);
+ DNSSECTimeToText(impl_->timeinception_, inception);
+
return (impl_->covered_.toText() +
" " + boost::lexical_cast<string>(static_cast<int>(impl_->algorithm_))
+ " " + boost::lexical_cast<string>(static_cast<int>(impl_->labels_))
+ " " + boost::lexical_cast<string>(impl_->originalttl_)
- + " " + boost::lexical_cast<string>(impl_->timeexpire_)
- + " " + boost::lexical_cast<string>(impl_->timeinception_)
+ + " " + expire
+ + " " + inception
+ " " + boost::lexical_cast<string>(impl_->keyid_)
+ " " + impl_->signer_.toText()
+ " " + encodeBase64(impl_->signature_));
Modified: trunk/src/lib/dns/cpp/rrclass-placeholder.h
==============================================================================
--- trunk/src/lib/dns/cpp/rrclass-placeholder.h (original)
+++ trunk/src/lib/dns/cpp/rrclass-placeholder.h Fri Feb 26 06:32:44 2010
@@ -238,16 +238,16 @@
// BEGIN_WELL_KNOWN_CLASS_DECLARATIONS
// END_WELL_KNOWN_CLASS_DECLARATIONS
+ static const RRClass& NONE();
+ static const RRClass& ANY();
+
+private:
// \brief Meta-classes
enum {
RRCLASS_RESERVED0 = 0,
RRCLASS_NONE = 254,
RRCLASS_ANY = 255
};
- static const RRClass& NONE();
- static const RRClass& ANY();
-
-private:
uint16_t classcode_;
};
Modified: trunk/src/lib/dns/cpp/rrset.cc
==============================================================================
--- trunk/src/lib/dns/cpp/rrset.cc (original)
+++ trunk/src/lib/dns/cpp/rrset.cc Fri Feb 26 06:32:44 2010
@@ -214,6 +214,15 @@
return (AbstractRRset::toWire(renderer));
}
+RRset::RRset(const Name& name, const RRClass& rrclass,
+ const RRType& rrtype, const RRTTL& ttl) :
+ BasicRRset(name, rrclass, rrtype, ttl)
+{
+ rrsig_ = RRsetPtr();
+}
+
+RRset::~RRset() {}
+
namespace {
class BasicRdataIterator : public RdataIterator {
private:
Modified: trunk/src/lib/dns/cpp/rrset.h
==============================================================================
--- trunk/src/lib/dns/cpp/rrset.h (original)
+++ trunk/src/lib/dns/cpp/rrset.h Fri Feb 26 06:32:44 2010
@@ -25,6 +25,7 @@
#include <exceptions/exceptions.h>
#include "rdata.h"
+#include "rrtype.h"
namespace isc {
namespace dns {
@@ -50,22 +51,20 @@
class BasicRRset;
class RdataIterator;
class BasicRRsetImpl;
-
-/// \brief A pointer-like type pointing to an \c AbstractRRset object.
+class RRset;
+
+/// \brief A pointer-like type pointing to an \c RRset object.
///
/// This type is commonly used as an argument of various functions defined
/// in this library in order to handle RRsets in a polymorphic manner.
-typedef boost::shared_ptr<AbstractRRset> RRsetPtr;
-
-/// \brief A pointer-like type pointing to an (immutable) \c AbstractRRset
+typedef boost::shared_ptr<RRset> RRsetPtr;
+
+/// \brief A pointer-like type pointing to an (immutable) \c RRset
/// object.
///
/// This type is commonly used as an argument of various functions defined
/// in this library in order to handle RRsets in a polymorphic manner.
-typedef boost::shared_ptr<const AbstractRRset> ConstRRsetPtr;
-
-/// \brief A convenient abbreviation for the most generic derived RRset class.
-typedef BasicRRset RRset;
+typedef boost::shared_ptr<const RRset> ConstRRsetPtr;
/// \brief A pointer-like type point to an \c RdataIterator object.
typedef boost::shared_ptr<RdataIterator> RdataIteratorPtr;
@@ -662,6 +661,69 @@
BasicRRsetImpl* impl_;
};
+/// \brief The \c RRset class is a concrete derived class of
+/// \c BasicRRset which contains a pointer to an additional RRset
+/// containing associated RRSIG records. This allows DNSSEC aware
+/// applications to treat data associated with a particular
+/// QNAME/QTYPE/QCLASS as a single object.
+class RRset : public BasicRRset {
+public:
+ explicit RRset(const Name& name, const RRClass& rrclass,
+ const RRType& rrtype, const RRTTL& ttl);
+
+ virtual ~RRset();
+
+ /// \brief Updates the owner name of the \c RRset, including RRSIGs if any
+ virtual void setName(const Name& n) {
+ BasicRRset::setName(n);
+ if (rrsig_) {
+ rrsig_->setName(n);
+ }
+ }
+
+ /// \brief Updates the owner name of the \c RRset, including RRSIGs if any
+ virtual void setTTL(const RRTTL& ttl) {
+ BasicRRset::setTTL(ttl);
+ if (rrsig_) {
+ rrsig_->setTTL(ttl);
+ }
+ }
+
+ /// \brief Adds an RRSIG RR to this RRset's signatures
+ virtual void addRRsig(const rdata::RdataPtr rdata) {
+ if (!rrsig_) {
+ rrsig_ = RRsetPtr(new RRset(this->getName(), this->getClass(),
+ RRType::RRSIG(), this->getTTL()));
+ }
+ rrsig_->addRdata(rdata);
+ }
+
+ /// \brief Adds an RRSIG RRset to this RRset
+ void addRRsig(AbstractRRset& sigs) {
+ RdataIteratorPtr it = sigs.getRdataIterator();
+
+ if (!rrsig_) {
+ rrsig_ = RRsetPtr(new RRset(this->getName(), this->getClass(),
+ RRType::RRSIG(), this->getTTL()));
+ }
+
+ for (it->first(); !it->isLast(); it->next()) {
+ rrsig_->addRdata(it->getCurrent());
+ }
+ }
+
+ void addRRsig(RRsetPtr sigs) { addRRsig(*sigs); }
+
+ /// \brief Clear the RRSIGs for this RRset
+ void removeRRsig() { rrsig_ = RRsetPtr(); }
+
+ /// \brief Return a pointer to this RRset's RRSIG RRset
+ RRsetPtr getRRsig() { return (rrsig_); }
+private:
+ RRsetPtr rrsig_;
+};
+
+
/// \brief Insert the \c RRset as a string into stream.
///
/// This method convert the \c rrset into a string and inserts it into the
Modified: trunk/src/lib/dns/cpp/rrtype-placeholder.h
==============================================================================
--- trunk/src/lib/dns/cpp/rrtype-placeholder.h (original)
+++ trunk/src/lib/dns/cpp/rrtype-placeholder.h Fri Feb 26 06:32:44 2010
@@ -251,12 +251,45 @@
// BEGIN_WELL_KNOWN_TYPE_DECLARATIONS
// END_WELL_KNOWN_TYPE_DECLARATIONS
+ static const RRType& IXFR();
+ static const RRType& AXFR();
+ static const RRType& ANY();
+
private:
+ // \brief Meta-classes
+ // XXX: these should be implemented using rrparamregistry
+ enum {
+ RRTYPE_IXFR = 251,
+ RRTYPE_AXFR = 252,
+ RRTYPE_ANY = 255
+ };
+
uint16_t typecode_;
};
// BEGIN_WELL_KNOWN_TYPE_DEFINITIONS
// END_WELL_KNOWN_TYPE_DEFINITIONS
+
+inline const RRType&
+RRType::IXFR()
+{
+ static RRType rrtype(RRTYPE_IXFR);
+ return (rrtype);
+}
+
+inline const RRType&
+RRType::AXFR()
+{
+ static RRType rrtype(RRTYPE_AXFR);
+ return (rrtype);
+}
+
+inline const RRType&
+RRType::ANY()
+{
+ static RRType rrtype(RRTYPE_ANY);
+ return (rrtype);
+}
///
/// \brief Insert the \c RRType as a string into stream.
Modified: trunk/src/lib/dns/cpp/tests/Makefile.am
==============================================================================
--- trunk/src/lib/dns/cpp/tests/Makefile.am (original)
+++ trunk/src/lib/dns/cpp/tests/Makefile.am Fri Feb 26 06:32:44 2010
@@ -16,12 +16,17 @@
run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc
run_unittests_SOURCES += rdata_cname_unittest.cc
+run_unittests_SOURCES += rdata_dname_unittest.cc
+run_unittests_SOURCES += rdata_dnskey_unittest.cc
+run_unittests_SOURCES += rdata_ds_unittest.cc
+run_unittests_SOURCES += rdata_nsec_unittest.cc
run_unittests_SOURCES += rdata_rrsig_unittest.cc
run_unittests_SOURCES += rrset_unittest.cc rrsetlist_unittest.cc
run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
run_unittests_SOURCES += message_unittest.cc
run_unittests_SOURCES += base64_unittest.cc
+run_unittests_SOURCES += hex_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
Modified: trunk/src/lib/dns/cpp/tests/base64_unittest.cc
==============================================================================
--- trunk/src/lib/dns/cpp/tests/base64_unittest.cc (original)
+++ trunk/src/lib/dns/cpp/tests/base64_unittest.cc Fri Feb 26 06:32:44 2010
@@ -43,11 +43,11 @@
test_sequence.push_back(StringPair("foobar", "Zm9vYmFy"));
}
vector<StringPair> test_sequence;
- vector<char> decoded_data;
+ vector<uint8_t> decoded_data;
};
void
-decodeCheck(const string& input_string, vector<char>& output,
+decodeCheck(const string& input_string, vector<uint8_t>& output,
const string& expected)
{
decodeBase64(input_string, output);
Modified: trunk/src/lib/dns/cpp/tests/name_unittest.cc
==============================================================================
--- trunk/src/lib/dns/cpp/tests/name_unittest.cc (original)
+++ trunk/src/lib/dns/cpp/tests/name_unittest.cc Fri Feb 26 06:32:44 2010
@@ -468,6 +468,12 @@
EXPECT_THROW(n1.concatenate(n2), TooLongName);
}
+TEST_F(NameTest, reverse)
+{
+ EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.reverse(),
+ Name("com.example.www."));
+}
+
TEST_F(NameTest, split)
{
// normal cases with or without explicitly specifying the trailing dot.
Modified: trunk/src/lib/dns/cpp/tests/rdata_rrsig_unittest.cc
==============================================================================
--- trunk/src/lib/dns/cpp/tests/rdata_rrsig_unittest.cc (original)
+++ trunk/src/lib/dns/cpp/tests/rdata_rrsig_unittest.cc Fri Feb 26 06:32:44 2010
@@ -36,20 +36,21 @@
// there's nothing to specialize
};
-TEST_F(Rdata_RRSIG_Test, fromText)
+TEST_F(Rdata_RRSIG_Test, fromText_RRSIG)
{
- string rrsig_txt("A 5 4 43200 1264801134 191145710 8496 isc.org. "
+ string rrsig_txt("A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
"evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
"diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
"NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
"f49t+sXKPzbipN9g+s1ZPiIyofc=");
generic::RRSIG rdata_rrsig(rrsig_txt);
EXPECT_EQ(rrsig_txt, rdata_rrsig.toText());
+
}
-TEST_F(Rdata_RRSIG_Test, toWireRenderer)
+TEST_F(Rdata_RRSIG_Test, toWireRenderer_RRSIG)
{
- string rrsig_txt("A 5 4 43200 1264801134 191145710 8496 isc.org. "
+ string rrsig_txt("A 5 4 43200 20100223214617 20100222214617 8496 isc.org. "
"evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
"diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
"NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
@@ -57,4 +58,5 @@
generic::RRSIG rdata_rrsig(rrsig_txt);
rdata_rrsig.toWire(renderer);
}
+
}
More information about the bind10-changes
mailing list