blob: d199e2957e1c9cee91c50391959e491751b9e074 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California.
*
* This file is part of NDNS (Named Data Networking Domain Name Service).
* See AUTHORS.md for complete list of NDNS authors and contributors.
*
* NDNS is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "logger.hpp"
#include "daemon/config-file.hpp"
#include "daemon/name-server.hpp"
#include "util/cert-helper.hpp"
#include "util/util.hpp"
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/program_options.hpp>
#include <iostream>
NDNS_LOG_INIT(NdnsDaemon);
namespace ndn {
namespace ndns {
/**
* @brief Name Server Daemon
* @note NdnsDaemon allows multiple name servers hosted by the same daemon, and they
* share same KeyChain, DbMgr, Validator and Face
*/
class NdnsDaemon : boost::noncopyable
{
public:
DEFINE_ERROR(Error, std::runtime_error);
NdnsDaemon(const std::string& configFile, Face& face, Face& validatorFace)
: m_face(face)
, m_validatorFace(validatorFace)
{
NDNS_LOG_INFO("ConfigFile = " << configFile);
ConfigFile config;
config.addSectionHandler("zones", bind(&NdnsDaemon::processZonesSection, this, _1));
config.parse(configFile, false);
}
void
processZonesSection(const ndn::ndns::ConfigSection& section)
{
if (section.begin() == section.end()) {
NDN_THROW(Error("zones section is empty"));
}
std::string dbFile = getDefaultDatabaseFile();
auto item = section.find("dbFile");
if (item != section.not_found()) {
dbFile = item->second.get_value<std::string>();
}
NDNS_LOG_INFO("DbFile = " << dbFile);
m_dbMgr = make_unique<DbMgr>(dbFile);
std::string validatorConfigFile(NDNS_CONFDIR "/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 = NdnsValidatorBuilder::create(m_validatorFace, 500, 0, validatorConfigFile);
for (const auto& option : section) {
Name name;
Name cert;
if (option.first == "zone") {
try {
name = option.second.get<Name>("name"); // exception leads to exit
}
catch (const std::exception&) {
NDNS_LOG_ERROR("Required `name' attribute missing in `zone' section");
NDN_THROW(Error("Required `name' attribute missing in `zone' section"));
}
try {
cert = option.second.get<Name>("cert");
}
catch (const std::exception&) {
// ignore
}
if (cert.empty()) {
try {
cert = CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain,
Name(name)
.append(label::NDNS_ITERATIVE_QUERY));
}
catch (const std::exception& e) {
NDNS_LOG_ERROR("Identity " << name << " does not have a default certificate: " << e.what());
NDN_THROW(Error("identity does not have default certificate"));
}
}
else {
try {
CertHelper::getCertificate(m_keyChain, name, cert);
} catch (const std::exception&) {
NDN_THROW(Error("Certificate `" + cert.toUri() + "` does not exist in the KeyChain"));
}
}
NDNS_LOG_TRACE("name = " << name << " cert = " << cert);
m_servers.push_back(make_shared<NameServer>(name, cert, m_face, *m_dbMgr,
m_keyChain, *m_validator));
}
} // for
}
private:
Face& m_face;
Face& m_validatorFace;
unique_ptr<security::Validator> m_validator;
unique_ptr<DbMgr> m_dbMgr;
std::vector<shared_ptr<NameServer>> m_servers;
KeyChain m_keyChain;
};
} // namespace ndns
} // namespace ndn
int
main(int argc, char* argv[])
{
std::string configFile(NDNS_CONFDIR "/ndns.conf");
namespace po = boost::program_options;
po::options_description optsDesc("Options");
optsDesc.add_options()
("help,h", "print this help message and exit")
("config-file,c", po::value<std::string>(&configFile)->default_value(configFile),
"path to configuration file")
;
po::variables_map vm;
try {
po::store(po::parse_command_line(argc, argv, optsDesc), vm);
po::notify(vm);
}
catch (const po::error& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
catch (const boost::bad_any_cast& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
if (vm.count("help") != 0) {
std::cout << "Usage: " << argv[0] << " [options]\n"
<< "\n"
<< optsDesc;
return 0;
}
boost::asio::io_service io;
ndn::Face face(io);
ndn::Face validatorFace(io);
try {
// NFD does not to forward Interests to the face it was received from.
// If the name server and its validator share the same face,
// the validator cannot be forwarded to the name server itself
// For now, two faces are used here.
// refs: https://redmine.named-data.net/issues/2206
// @TODO enhance validator to get the certificate from the local db if present
ndn::ndns::NdnsDaemon daemon(configFile, face, validatorFace);
face.processEvents();
}
catch (const std::exception& e) {
NDNS_LOG_FATAL(e.what());
return 1;
}
return 0;
}