nrd-config: Adding processing of command line arguments and processing of conf file.
refs #1450
Change-Id: I18fa5c1c12ec2367670659be331a9f95e0a920eb
diff --git a/nrd.conf.sample b/nrd.conf.sample
new file mode 100644
index 0000000..35b162f
--- /dev/null
+++ b/nrd.conf.sample
@@ -0,0 +1,70 @@
+security
+{
+ ; Security section defines the trust model that NRD should use. It consists of rules and
+ ; trust-anchors, which are briefly defined in this file. For more details please see the
+ ; following wiki:
+ ; http://redmine.named-data.net/projects/ndn-cpp-dev/wiki/CommandValidatorConf
+ ;
+ ; A trust-anchor is a pre-trusted certificate. It is usually stored in a file in the
+ ; same directory as this config file. You can download the NDN testbed root certificate as the
+ ; trust anchor, or you can dump an existing certificate from your system as a trust anchor:
+ ; $ ndnsec cert-dump /example/certificate/name > trust-anchor.cert
+ ; or you can generate a self-signed certificate as a trust anchor:
+ ; $ ndnsec key-gen /example/identity/name > trust-anchor.cert
+ ; See comments in trust-anchor section for configuration details.
+ ;
+ ; A rule defines conditions a valid packet MUST have. A packet must satisfy one of the rules defined
+ ; here. A rule can be broken into two parts: matching & checking. A packet will be matched against
+ ; rules from the first to the last until a matched rule is encountered. The matched rule will be
+ ; used to check the packet. If a packet does not match any rule, it will be treated as invalid.
+ ; The matching part of a rule consists of `for` and `filter` sections. They collectively define
+ ; which packets can be checked with this rule. `for` defines packet type (data or interest),
+ ; while `filter` defines conditions on other properties of a packet. Right now, you can only
+ ; define conditions on packet name, and you can only specify ONLY ONE filter for packet name.
+ ; The checking part of a rule consists of `checker`, which defines the conditions that a VALID
+ ; packet MUST have. See comments in checker section for more details.
+
+ rule
+ {
+ id "NRD Prefix Registration Command Rule" ; rule id
+ for interest ; this rule is used to validate interests
+ filter
+ {
+ type name ; condition on interest name (w/o signature)
+ regex ^[<localhop><localhost>]<nrd>[<register><unregister>]<>{3}$
+ }
+ checker
+ {
+ type customized
+ sig-type rsa-sha256 ; interest must have a rsa-sha256 signature
+ key-locator
+ {
+ type name ; key locator must be the certificate name of
+ ; the signing key
+ regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$
+ }
+ }
+ }
+ rule
+ {
+ id "Testbed Hierarchy Rule" ; rule id
+ for data ; this rule is used to validate data
+ filter
+ {
+ type name ; condition on data name
+ regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$
+ }
+ checker
+ {
+ type hierarchical ; the certificate name of the signing key and
+ ; the data name must follow the hierarchical model
+ sig-type rsa-sha256 ; data must have a rsa-sha256 signature
+ }
+ }
+ trust-anchor
+ {
+ type file ; trust anchor is stored in a file
+ file-name "trust-anchor.cert" ; the file name, by default this file should be placed in the
+ ; same folder as this config file.
+ }
+}
diff --git a/src/common.hpp b/src/common.hpp
index 650f2de..f520828 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -22,5 +22,24 @@
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex_find_format.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/info_parser.hpp>
+#include "../build/src/config.hpp"
+
+namespace ndn {
+namespace nrd {
+
+class Error : public std::runtime_error
+{
+public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+};
+
+} //namespace nrd
+} //namespace ndn
#endif // NRD_COMMON_HPP
diff --git a/src/main.cpp b/src/main.cpp
index e360e5d..5d0e5ed 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,21 +4,97 @@
* See COPYING for copyright and distribution information.
*/
+#include "common.hpp"
#include "nrd.hpp"
+#include "nrd-config.hpp"
+#include <getopt.h>
+
+struct ProgramOptions
+{
+ bool showUsage;
+ std::string config;
+};
+
+static void
+printUsage(std::ostream& os, const std::string& programName)
+{
+ os << "Usage: \n"
+ << " " << programName << " [options]\n"
+ << "\n"
+ << "Run NRD daemon\n"
+ << "\n"
+ << "Options:\n"
+ << " [--help] - print this help message\n"
+ << " [--config /path/to/nrd.conf] - path to configuration file "
+ << "(default: " << DEFAULT_CONFIG_FILE << ")\n"
+ ;
+}
+
+static bool
+parseCommandLine(int argc, char** argv, ProgramOptions& options)
+{
+ options.showUsage = false;
+ options.config = DEFAULT_CONFIG_FILE;
+
+ while (true) {
+ int optionIndex = 0;
+ static ::option longOptions[] = {
+ { "help" , no_argument , 0, 0 },
+ { "config" , required_argument, 0, 0 },
+ { 0 , 0 , 0, 0 }
+ };
+ int c = getopt_long_only(argc, argv, "", longOptions, &optionIndex);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ switch (optionIndex) {
+ case 0: // help
+ options.showUsage = true;
+ break;
+ case 1: // config
+ options.config = ::optarg;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
int
main(int argc, char** argv)
{
- try {
- // TODO: the configFilename should be obtained from command line arguments.
- std::string configFilename("nrd.conf");
+ //processing command line arguments, if available
+ ProgramOptions options;
+ bool isCommandLineValid = parseCommandLine(argc, argv, options);
+ if (!isCommandLineValid) {
+ printUsage(std::cerr, argv[0]);
+ return 1;
+ }
+ if (options.showUsage) {
+ printUsage(std::cout, argv[0]);
+ return 0;
+ }
- ndn::nrd::Nrd nrd(configFilename);
+ //Now read the config file and pass the security section to validator
+ try {
+ std::string configFilename(options.config);
+
+ ndn::nrd::NrdConfig config;
+ config.load(configFilename);
+ ndn::nrd::ConfigSection securitySection = config.getSecuritySection();
+
+ ndn::nrd::Nrd nrd(securitySection, configFilename);
nrd.enableLocalControlHeader();
nrd.listen();
}
catch (std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
}
+
return 0;
}
diff --git a/src/nrd-config.cpp b/src/nrd-config.cpp
new file mode 100644
index 0000000..c6181f9
--- /dev/null
+++ b/src/nrd-config.cpp
@@ -0,0 +1,116 @@
+#include "nrd-config.hpp"
+
+namespace ndn {
+namespace nrd {
+
+NrdConfig::NrdConfig()
+ : m_isSecuritySectionDefined(false)
+{
+}
+
+void
+NrdConfig::load(const std::string& filename)
+{
+ std::ifstream inputFile;
+ inputFile.open(filename.c_str());
+ if (!inputFile.good() || !inputFile.is_open())
+ {
+ std::string msg = "Failed to read configuration file: ";
+ msg += filename;
+ std::cerr << filename << std::endl;
+ throw Error(msg);
+ }
+ load(inputFile, filename);
+ inputFile.close();
+}
+
+void
+NrdConfig::load(const std::string& input, const std::string& filename)
+{
+ std::istringstream inputStream(input);
+ load(inputStream, filename);
+}
+
+void
+NrdConfig::load(std::istream& input, const std::string& filename)
+{
+ BOOST_ASSERT(!filename.empty());
+
+ ConfigSection ptree;
+ try
+ {
+ boost::property_tree::read_info(input, ptree);
+ }
+ catch (const boost::property_tree::info_parser_error& error)
+ {
+ std::stringstream msg;
+ msg << "Failed to parse configuration file";
+ msg << " " << filename;
+ msg << " " << error.message() << " line " << error.line();
+ throw Error(msg.str());
+ }
+ process(ptree, filename);
+}
+
+void
+NrdConfig::process(const ConfigSection& configSection,
+ const std::string& filename)
+{
+ BOOST_ASSERT(!filename.empty());
+
+ if (configSection.begin() == configSection.end())
+ {
+ std::string msg = "Error processing configuration file";
+ msg += ": ";
+ msg += filename;
+ msg += " no data";
+ throw Error(msg);
+ }
+
+ for (ConfigSection::const_iterator i = configSection.begin();
+ i != configSection.end(); ++i)
+ {
+ const std::string& sectionName = i->first;
+ const ConfigSection& section = i->second;
+
+ if (boost::iequals(sectionName, "security"))
+ {
+ onSectionSecurity(section, filename);
+ }
+ //Add more sections here as needed
+ //else if (boost::iequals(sectionName, "another-section"))
+ //{
+ //onSectionAnotherSection(section, filename);
+ //}
+ else
+ {
+ std::string msg = "Error processing configuration file";
+ msg += " ";
+ msg += filename;
+ msg += " unrecognized section: " + sectionName;
+ throw Error(msg);
+ }
+ }
+}
+
+void
+NrdConfig::onSectionSecurity(const ConfigSection& section,
+ const std::string& filename)
+{
+ if (!m_isSecuritySectionDefined) {
+ //setSecturitySection(section);
+ m_securitySection = section;
+ m_filename = filename;
+ m_isSecuritySectionDefined = true;
+ }
+ else {
+ std::string msg = "Error processing configuration file";
+ msg += " ";
+ msg += filename;
+ msg += " security section can appear only once";
+ throw Error(msg);
+ }
+}
+
+} //namespace nrd
+} //namespace ndn
diff --git a/src/nrd-config.hpp b/src/nrd-config.hpp
new file mode 100644
index 0000000..ee119f6
--- /dev/null
+++ b/src/nrd-config.hpp
@@ -0,0 +1,61 @@
+#ifndef NRD_CONFIG_HPP
+#define NRD_CONFIG_HPP
+
+#include "common.hpp"
+
+namespace ndn {
+namespace nrd {
+
+typedef boost::property_tree::ptree ConfigSection;
+
+class NrdConfig
+{
+
+public:
+ NrdConfig();
+
+ virtual
+ ~NrdConfig()
+ {
+ }
+
+ void
+ load(const std::string& filename);
+
+ void
+ load(const std::string& input, const std::string& filename);
+
+ void
+ load(std::istream& input, const std::string& filename);
+
+ const ConfigSection&
+ getSecuritySection() const
+ {
+ return m_securitySection;
+ }
+
+private:
+ void
+ process(const ConfigSection& configSection,
+ const std::string& filename);
+
+ void
+ onSectionSecurity(const ConfigSection& section,
+ const std::string& filename);
+
+ const void
+ setSecturitySection(const ConfigSection& securitySection)
+ {
+ m_securitySection = securitySection;
+ }
+
+private:
+ bool m_isSecuritySectionDefined;
+ ConfigSection m_securitySection;
+ std::string m_filename;
+};
+
+}//namespace nrd
+}//namespace ndn
+
+#endif // NRD_CONFIG_HPP
diff --git a/src/nrd.cpp b/src/nrd.cpp
index 09db6b2..492f9c2 100644
--- a/src/nrd.cpp
+++ b/src/nrd.cpp
@@ -34,7 +34,8 @@
),
};
-Nrd::Nrd(const std::string& validatorConfig)
+Nrd::Nrd(const ndn::nrd::ConfigSection& securitySection,
+ const std::string& validatorConfig)
: m_face(new Face())
, m_nfdController(new nfd::Controller(*m_face))
, m_validator(m_face)
@@ -45,7 +46,8 @@
//check whether the components of localhop and localhost prefixes are same
BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
- m_validator.load(validatorConfig);
+ //m_validator.load(validatorConfig);
+ m_validator.load(securitySection, validatorConfig);
std::cerr << "Setting interest filter on: " << COMMAND_PREFIX.toUri() << std::endl;
m_face->setController(m_nfdController);
@@ -70,7 +72,6 @@
m_face->shutdown();
}
-
void
Nrd::sendResponse(const Name& name,
const nfd::ControlResponse& response)
@@ -230,7 +231,6 @@
sendResponse(request.getName(), response);
}
-
void
Nrd::insertEntry(const Interest& request, const PrefixRegOptions& options)
{
@@ -248,7 +248,6 @@
bind(&Nrd::onCommandError, this, _1, _2, request, options));
}
-
void
Nrd::deleteEntry(const Interest& request, const PrefixRegOptions& options)
{
@@ -260,7 +259,6 @@
bind(&Nrd::onCommandError, this, _1, _2, request, options));
}
-
void
Nrd::listen()
{
@@ -268,14 +266,12 @@
m_face->processEvents();
}
-
void
Nrd::onControlHeaderSuccess()
{
std::cout << "Local control header enabled" << std::endl;
}
-
void
Nrd::onControlHeaderError(uint32_t code, const std::string& reason)
{
@@ -298,9 +294,10 @@
Nrd::onNotification(const nfd::FaceEventNotification& notification)
{
/// \todo A notification can be missed, in this case check Facelist
- if (notification.getKind() == 2) { //face destroyed
- m_managedRib.erase(notification.getFaceId());
- }
+ std::cerr << "Notification Rcvd: " << notification << std::endl;
+ if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) { //face destroyed
+ m_managedRib.erase(notification.getFaceId());
+ }
}
} // namespace nrd
diff --git a/src/nrd.hpp b/src/nrd.hpp
index b441de8..d6007d7 100644
--- a/src/nrd.hpp
+++ b/src/nrd.hpp
@@ -9,15 +9,16 @@
#include "rib.hpp"
#include "face-monitor.hpp"
+#include "nrd-config.hpp"
namespace ndn {
namespace nrd {
-class Nrd
+class Nrd : noncopyable
{
public:
- explicit
- Nrd(const std::string& validatorConfig);
+ Nrd(const ndn::nrd::ConfigSection& securitySection,
+ const std::string& validatorConfig);
void
onRibRequest(const Interest& request);
diff --git a/validator.conf.sample b/validator.conf.sample
deleted file mode 100644
index 224d3d8..0000000
--- a/validator.conf.sample
+++ /dev/null
@@ -1,40 +0,0 @@
-rule
-{
- id "NRD Prefix Registration Command Rule"
- for interest
- filter
- {
- type name
- regex ^<localhost><nrd>[<register><unregister>]<>{3}$
- }
- checker
- {
- type customized
- sig-type rsa-sha256
- key-locator
- {
- type name
- regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT>$
- }
- }
-}
-rule
-{
- id "Testbed Hierarchy Rule"
- for data
- filter
- {
- type name
- regex ^[^<KEY>]*<KEY><>*<ksk-.*><ID-CERT><>$
- }
- checker
- {
- type hierarchical
- sig-type rsa-sha256
- }
-}
-trust-anchor
-{
- type file
- file-name "trust-anchor.cert"
-}
\ No newline at end of file
diff --git a/wscript b/wscript
index 89c8f40..f25aebf 100644
--- a/wscript
+++ b/wscript
@@ -39,6 +39,7 @@
# except:
# pass
+ conf.define('DEFAULT_CONFIG_FILE', '%s/ndn/nrd.conf' % conf.env['SYSCONFDIR'])
conf.write_config_header('src/config.hpp')
def build (bld):
@@ -65,4 +66,7 @@
use='nrd-objects',
includes=['.', 'src'],
install_prefix=None,
- )
+ )
+
+ bld.install_files('${SYSCONFDIR}/ndn', 'nrd.conf.sample')
+