tools/ndns-daemon: fix bug that validator cannot fetch certificate
refs #2206
Change-Id: I10c69d95e6a5fd020038211ce419763fd62afcb3
diff --git a/ndns.conf.sample.in b/ndns.conf.sample.in
index 71e26a2..b2b968a 100644
--- a/ndns.conf.sample.in
+++ b/ndns.conf.sample.in
@@ -1,6 +1,7 @@
zones
{
- ; dbFile /usr/local/var/ndns/ndns.db
+ ; dbFile @DEFAULT_DATABASE_PATH@/ndns.db
+ ; validatorConfigFile @DEFAULT_CONFIG_PATH@/validator.conf
zone
{
@@ -18,6 +19,7 @@
; omit cert to select the default certificate of above identity
; }
}
+
hints
{
; hint /ucla
diff --git a/src/daemon/name-server.cpp b/src/daemon/name-server.cpp
index 072e889..b02a423 100644
--- a/src/daemon/name-server.cpp
+++ b/src/daemon/name-server.cpp
@@ -137,7 +137,9 @@
m_validator.validate(*data,
bind(&NameServer::doUpdate, this, interest.shared_from_this(), data),
[this] (const shared_ptr<const Data>& data, const std::string& msg) {
- NDNS_LOG_WARN("Ignoring update that did not pass the verification");
+ NDNS_LOG_WARN("Ignoring update that did not pass the verification. "
+ << "Validator cannot fetch certificate from the face "
+ << "that used by validator itself to send Interest");
});
}
}
@@ -213,7 +215,8 @@
blk.push_back(nonNegativeIntegerBlock(ndn::ndns::tlv::UpdateReturnCode, UPDATE_FAILURE));
blk.encode(); // must
answer->setContent(blk);
- NDNS_LOG_INFO("Error processing the update: " << e.what());
+ NDNS_LOG_INFO("Error processing the update: " << e.what()
+ << ". Update may need sudo privilege to write DbFile");
NDNS_LOG_TRACE("exception happens and answer update with UPDATE_FAILURE");
}
m_keyChain.sign(*answer, m_certName);
diff --git a/tests/unit/daemon/name-server.cpp b/tests/unit/daemon/name-server.cpp
index 578533d..f721a5e 100644
--- a/tests/unit/daemon/name-server.cpp
+++ b/tests/unit/daemon/name-server.cpp
@@ -41,7 +41,7 @@
public:
NameServerFixture()
: face(ndn::util::makeDummyClientFace({ false, true }))
- , zone(m_net.getName())
+ , zone(m_root.getName())
, validator(*face)
, server(zone, m_certName, *face, m_session, m_keyChain, validator)
{
@@ -69,7 +69,7 @@
BOOST_AUTO_TEST_CASE(NdnsQuery)
{
Query q(hint, zone, ndns::label::NDNS_ITERATIVE_QUERY);
- q.setRrLabel(Name("ndnsim"));
+ q.setRrLabel(Name("net"));
q.setRrType(ndns::label::NS_RR_TYPE);
bool hasDataBack = false;
@@ -125,7 +125,7 @@
BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RAW);
};
- q.setRrLabel("dsk-3");
+ q.setRrLabel("dsk-1");
face->receive(q.toInterest());
run();
@@ -138,7 +138,7 @@
Response re;
re.setZone(zone);
re.setQueryType(label::NDNS_ITERATIVE_QUERY);
- re.setRrLabel(Name("ndnsim"));
+ re.setRrLabel(Name("net"));
re.setRrType(label::NS_RR_TYPE);
re.setNdnsType(NDNS_RESP);
@@ -191,7 +191,7 @@
Response re;
re.setZone(zone);
re.setQueryType(label::NDNS_ITERATIVE_QUERY);
- re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
+ re.setRrLabel(Name("net-XYZ")); // insert new records
re.setRrType(label::NS_RR_TYPE);
re.setNdnsType(NDNS_RESP);
@@ -239,6 +239,188 @@
BOOST_CHECK_EQUAL(hasDataBack, true);
}
+BOOST_AUTO_TEST_CASE(UpdateValidatorCannotFetchCert)
+{
+ Name dskName = m_keyChain.generateRsaKeyPair(TEST_IDENTITY_NAME, false);
+ std::vector<CertificateSubjectDescription> desc;
+ time::system_clock::TimePoint notBefore = time::system_clock::now();
+ time::system_clock::TimePoint notAfter = notBefore + time::days(365);
+ shared_ptr<IdentityCertificate> dskCert =
+ m_keyChain.prepareUnsignedIdentityCertificate(dskName, m_certName,
+ notBefore, notAfter, desc);
+
+ m_keyChain.sign(*dskCert, m_certName);
+ m_keyChain.addCertificateAsKeyDefault(*dskCert);
+ NDNS_LOG_TRACE("KeyChain: add cert: " << dskCert->getName() << ". KeyLocator: "
+ << dskCert->getSignature().getKeyLocator().getName());
+
+ Rrset rrset(&m_root);
+ Name label = dskCert->getName().getPrefix(-2).getSubName(m_root.getName().size() + 1);
+ rrset.setLabel(label);
+ rrset.setType(label::CERT_RR_TYPE);
+ rrset.setVersion(dskCert->getName().get(-1));
+ rrset.setTtl(m_root.getTtl());
+ rrset.setData(dskCert->wireEncode());
+ m_session.insert(rrset);
+ NDNS_LOG_TRACE("DB: zone " << m_root << " add a ID-CERT RR with name="
+ << dskCert->getName() << " rrLabel=" << label);
+
+ Response re;
+ re.setZone(zone);
+ re.setQueryType(label::NDNS_ITERATIVE_QUERY);
+ re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
+ re.setRrType(label::NS_RR_TYPE);
+ re.setNdnsType(NDNS_RESP);
+
+ std::string str = "ns1.ndnsim.net";
+ re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+ str = "ns2.ndnsim.net";
+ re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+
+ shared_ptr<Data> data = re.toData();
+ m_keyChain.sign(*data, dskCert->getName());
+
+ Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
+ const Block& block = data->wireEncode();
+ Name name;
+ name.append(block);
+
+ q.setRrLabel(name);
+ q.setRrType(label::NDNS_UPDATE_LABEL);
+
+ bool hasDataBack = false;
+
+ // no data back, since the Update cannot pass verification
+ face->onData += [&] (const Data& data) {
+ hasDataBack = true;
+ BOOST_FAIL("UNEXPECTED");
+ };
+
+ face->receive(q.toInterest());
+ run();
+
+ BOOST_CHECK_EQUAL(hasDataBack, false);
+}
+
+class NameServerFixture2 : public DbTestData
+{
+public:
+ NameServerFixture2()
+ : face(ndn::util::makeDummyClientFace(io, { false, true }))
+ , validatorFace(ndn::util::makeDummyClientFace(io, { false, true }))
+ , zone(m_root.getName())
+ , validator(*validatorFace) // different face for validator
+ , server(zone, m_certName, *face, m_session, m_keyChain, validator)
+ {
+ // ensure prefix is registered
+ run();
+ validatorFace->onInterest += [&] (const Interest& interest) {
+ NDNS_LOG_TRACE("validatorFace get Interest: " << interest.getName());
+ face->receive(interest);
+ };
+ }
+
+ void
+ run()
+ {
+ io.poll();
+ io.reset();
+ }
+
+public:
+ boost::asio::io_service io;
+ shared_ptr<ndn::util::DummyClientFace> face;
+ shared_ptr<ndn::util::DummyClientFace> validatorFace;
+ Name hint;
+ const Name& zone;
+ Validator validator;
+ ndns::NameServer server;
+};
+
+BOOST_FIXTURE_TEST_CASE(UpdateValidatorFetchCert, NameServerFixture2)
+{
+ Name dskName = m_keyChain.generateRsaKeyPair(TEST_IDENTITY_NAME, false);
+ std::vector<CertificateSubjectDescription> desc;
+ time::system_clock::TimePoint notBefore = time::system_clock::now();
+ time::system_clock::TimePoint notAfter = notBefore + time::days(365);
+ shared_ptr<IdentityCertificate> dskCert =
+ m_keyChain.prepareUnsignedIdentityCertificate(dskName, m_certName,
+ notBefore, notAfter, desc);
+
+ m_keyChain.sign(*dskCert, m_certName);
+ m_keyChain.addCertificateAsKeyDefault(*dskCert);
+ NDNS_LOG_TRACE("KeyChain: add cert: " << dskCert->getName() << ". KeyLocator: "
+ << dskCert->getSignature().getKeyLocator().getName());
+
+ Rrset rrset(&m_root);
+ Name label = dskCert->getName().getPrefix(-2).getSubName(m_root.getName().size() + 1);
+ rrset.setLabel(label);
+ rrset.setType(label::CERT_RR_TYPE);
+ rrset.setVersion(dskCert->getName().get(-1));
+ rrset.setTtl(m_root.getTtl());
+ rrset.setData(dskCert->wireEncode());
+ m_session.insert(rrset);
+ NDNS_LOG_TRACE("DB: zone " << m_root << " add a ID-CERT RR with name="
+ << dskCert->getName() << " rrLabel=" << label);
+
+ Response re;
+ re.setZone(zone);
+ re.setQueryType(label::NDNS_ITERATIVE_QUERY);
+ re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
+ re.setRrType(label::NS_RR_TYPE);
+ re.setNdnsType(NDNS_RESP);
+
+ std::string str = "ns1.ndnsim.net";
+ re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+ str = "ns2.ndnsim.net";
+ re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
+
+ shared_ptr<Data> data = re.toData();
+ m_keyChain.sign(*data, dskCert->getName());
+
+ Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
+ const Block& block = data->wireEncode();
+ Name name;
+ name.append(block);
+
+ q.setRrLabel(name);
+ q.setRrType(label::NDNS_UPDATE_LABEL);
+
+ bool hasDataBack = false;
+
+ shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT><>");
+ face->onData += [&] (const Data& data) {
+ if (regex->match(data.getName())) {
+ validatorFace->receive(data); // It's data requested by validator
+ }
+ else {
+ // cert is requested by validator
+ hasDataBack = true;
+ NDNS_LOG_TRACE("get Data back");
+ BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
+ Response resp;
+
+ BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
+ std::cout << resp << std::endl;
+ BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
+ BOOST_CHECK_GT(resp.getRrs().size(), 0);
+ Block block = resp.getRrs()[0];
+ block.parse();
+ int ret = -1;
+ BOOST_CHECK_EQUAL(block.type(), ndns::tlv::RrData);
+ Block::element_const_iterator val = block.elements_begin();
+ BOOST_CHECK_EQUAL(val->type(), ndns::tlv::UpdateReturnCode); // the first must be return code
+ ret = readNonNegativeInteger(*val);
+ BOOST_CHECK_EQUAL(ret, 0);
+ }
+ };
+
+ face->receive(q.toInterest());
+ run();
+
+ BOOST_CHECK_EQUAL(hasDataBack, true);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
diff --git a/tools/ndns-daemon.cpp b/tools/ndns-daemon.cpp
index 463022a..5937562 100644
--- a/tools/ndns-daemon.cpp
+++ b/tools/ndns-daemon.cpp
@@ -36,18 +36,17 @@
*/
class NdnsDaemon : noncopyable
{
+public:
DEFINE_ERROR(Error, std::runtime_error);
-public:
explicit
- NdnsDaemon(const std::string& configFile, Face& face)
- : m_configFile(configFile)
- , m_face(face)
- , m_validator(face)
+ NdnsDaemon(const std::string& configFile, Face& face, Face& validatorFace)
+ : m_face(face)
+ , m_validatorFace(validatorFace)
{
try {
ConfigFile config;
- NDNS_LOG_TRACE("configFile: " << configFile);
+ NDNS_LOG_INFO("NnsnDaemon ConfigFile = " << configFile);
config.addSectionHandler("zones",
bind(&NdnsDaemon::processZonesSection, this, _1, _3));
@@ -88,16 +87,21 @@
throw Error("zones section is empty");
}
+ std::string dbFile = DEFAULT_DATABASE_PATH "/" "ndns.db";
ConfigSection::const_assoc_iterator item = section.find("dbFile");
if (item != section.not_found()) {
- m_dbFile = item->second.get_value<std::string>();
+ dbFile = item->second.get_value<std::string>();
}
- else {
- m_dbFile = "/usr/local/var/ndns/ndns.db";
- }
- NDNS_LOG_TRACE("dbFile " << m_dbFile);
+ NDNS_LOG_INFO("DbFile = " << dbFile);
+ m_dbMgr = unique_ptr<DbMgr>(new DbMgr(dbFile));
- m_dbMgr = make_shared<DbMgr>(m_dbFile);
+ std::string validatorConfigFile = DEFAULT_CONFIG_PATH "/" "validator.conf";
+ item = section.find("validatorConfigFile");
+ if (item != section.not_found()) {
+ validatorConfigFile = item->second.get_value<std::string>();
+ }
+ NDNS_LOG_INFO("ValidatorConfigFile = " << validatorConfigFile);
+ m_validator = unique_ptr<Validator>(new Validator(m_validatorFace, validatorConfigFile));
for (const auto& option : section) {
Name name;
@@ -117,8 +121,21 @@
;
}
+
+ if (!m_keyChain.doesIdentityExist(name)) {
+ NDNS_LOG_FATAL("Identity: " << name << " does not exist in the KeyChain");
+ throw Error("Identity does not exist in the KeyChain");
+ }
+
if (cert.empty()) {
- cert = m_keyChain.getDefaultCertificateNameForIdentity(name);
+ try {
+ cert = m_keyChain.getDefaultCertificateNameForIdentity(name);
+ }
+ catch (std::exception& e) {
+ NDNS_LOG_FATAL("Identity: " << name << " does not have default certificate. "
+ << e.what());
+ throw Error("identity does not have default certificate");
+ }
}
else {
if (!m_keyChain.doesCertificateExist(cert)) {
@@ -127,18 +144,17 @@
}
NDNS_LOG_TRACE("name = " << name << " cert = " << cert);
m_servers.push_back(make_shared<NameServer>(name, cert, m_face, *m_dbMgr,
- m_keyChain, m_validator));
+ m_keyChain, *m_validator));
}
} // for
}
private:
- std::string m_configFile;
Face& m_face;
- Validator m_validator;
- std::string m_dbFile;
- shared_ptr<DbMgr> m_dbMgr;
- std::vector<shared_ptr<NameServer> > m_servers;
+ Face& m_validatorFace;
+ unique_ptr<Validator> m_validator;
+ unique_ptr<DbMgr> m_dbMgr;
+ std::vector<shared_ptr<NameServer>> m_servers;
KeyChain m_keyChain;
};
@@ -194,21 +210,24 @@
return 1;
}
+ boost::asio::io_service io;
+ ndn::Face face(io);
+ ndn::Face validatorFace(io);
+
try {
- ndn::Face face;
- NdnsDaemon nsd(configFile, face);
+ // NFD does not to forward Interests to the face it was received from.
+ // If the name server and its validator share same face,
+ // the validator cannot be forwarded to the name server itself
+ // refs: http://redmine.named-data.net/issues/2206
+ // @TODO enhance validator to get the certificate from the local db if it has
- boost::asio::signal_set signalSet(face.getIoService(), SIGINT, SIGTERM);
-
- signalSet.async_wait([&face] (const boost::system::error_code&, const int) {
- face.getIoService().stop();
- });
+ NdnsDaemon daemon(configFile, face, validatorFace);
face.processEvents();
}
catch (std::exception& e) {
NDNS_LOG_FATAL("ERROR: " << e.what());
- return 2;
+ return 1;
}
return 0;
diff --git a/wscript b/wscript
index dd3807e..26f4fc8 100644
--- a/wscript
+++ b/wscript
@@ -98,6 +98,8 @@
name='validator-sample',
ANCHORPATH='anchors/root.cert',
RELATION='is-prefix-of',
+ DEFAULT_CONFIG_PATH="%s/ndns" % bld.env['SYSCONFDIR'],
+ DEFAULT_DATABASE_PATH="%s/ndns" % bld.env['LOCALSTATEDIR'],
help='the validator configuration of ndns',
)