BIND 10 trac2957, updated. 95d6573794927ff46242625736d894ca4758f55a [2957] Review comments. Added in the ability to configure TSIG Key information.
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jun 28 20:44:31 UTC 2013
The branch, trac2957 has been updated
via 95d6573794927ff46242625736d894ca4758f55a (commit)
from ae6f706d85ae90ca971d2cfef2abfe7e5bc7856d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 95d6573794927ff46242625736d894ca4758f55a
Author: Thomas Markwalder <tmark at isc.org>
Date: Fri Jun 28 16:43:09 2013 -0400
[2957] Review comments. Added in the ability to configure TSIG Key
information.
-----------------------------------------------------------------------
Summary of changes:
src/bin/d2/d2_cfg_mgr.cc | 33 +-
src/bin/d2/d2_cfg_mgr.h | 21 +-
src/bin/d2/d2_config.cc | 364 ++++++++++++++-------
src/bin/d2/d2_config.h | 344 +++++++++++++++++---
src/bin/d2/d2_messages.mes | 16 +-
src/bin/d2/d_cfg_mgr.cc | 55 ++--
src/bin/d2/d_cfg_mgr.h | 71 +++--
src/bin/d2/dhcp-ddns.spec | 36 ++-
src/bin/d2/tests/d2_cfg_mgr_unittests.cc | 513 ++++++++++++++++++++++++++----
src/bin/d2/tests/d_cfg_mgr_unittests.cc | 18 +-
src/bin/d2/tests/d_test_stubs.cc | 9 +-
src/bin/d2/tests/d_test_stubs.h | 10 +-
12 files changed, 1191 insertions(+), 299 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/bin/d2/d2_cfg_mgr.cc b/src/bin/d2/d2_cfg_mgr.cc
index 0b94c6e..07068d6 100644
--- a/src/bin/d2/d2_cfg_mgr.cc
+++ b/src/bin/d2/d2_cfg_mgr.cc
@@ -30,7 +30,8 @@ namespace d2 {
D2CfgContext::D2CfgContext()
: forward_mgr_(new DdnsDomainListMgr("forward_mgr")),
- reverse_mgr_(new DdnsDomainListMgr("reverse_mgr")) {
+ reverse_mgr_(new DdnsDomainListMgr("reverse_mgr")),
+ keys_(new TSIGKeyInfoMap()) {
}
D2CfgContext::D2CfgContext(const D2CfgContext& rhs) : DCfgContextBase(rhs) {
@@ -43,6 +44,8 @@ D2CfgContext::D2CfgContext(const D2CfgContext& rhs) : DCfgContextBase(rhs) {
reverse_mgr_.reset(new DdnsDomainListMgr(rhs.reverse_mgr_->getName()));
reverse_mgr_->setDomains(rhs.reverse_mgr_->getDomains());
}
+
+ keys_ = rhs.keys_;
}
D2CfgContext::~D2CfgContext() {
@@ -51,6 +54,14 @@ D2CfgContext::~D2CfgContext() {
// *********************** D2CfgMgr *************************
D2CfgMgr::D2CfgMgr() : DCfgMgrBase(DCfgContextBasePtr(new D2CfgContext())) {
+ // TSIG keys need to parse before the Domains, so we can catch Domains
+ // that specify undefined keys. Create the necessary parsing order now.
+ addToParseOrder("interface");
+ addToParseOrder("ip_address");
+ addToParseOrder("port");
+ addToParseOrder("tsig_keys");
+ addToParseOrder("forward_ddns");
+ addToParseOrder("reverse_ddns");
}
D2CfgMgr::~D2CfgMgr() {
@@ -58,13 +69,13 @@ D2CfgMgr::~D2CfgMgr() {
bool
D2CfgMgr::matchForward(const std::string& fqdn, DdnsDomainPtr& domain) {
- if (fqdn == "") {
+ if (fqdn.empty()) {
// This is a programmatic error and should not happen.
- isc_throw (D2CfgError, "matchForward passed an empty fqdn");
+ isc_throw(D2CfgError, "matchForward passed an empty fqdn");
}
// Fetch the forward manager from the D2 context.
- DdnsDomainListMgrPtr& mgr = getD2CfgContext()->getForwardMgr();
+ DdnsDomainListMgrPtr mgr = getD2CfgContext()->getForwardMgr();
// Call the manager's match method and return the result.
return (mgr->matchDomain(fqdn, domain));
@@ -72,13 +83,13 @@ D2CfgMgr::matchForward(const std::string& fqdn, DdnsDomainPtr& domain) {
bool
D2CfgMgr::matchReverse(const std::string& fqdn, DdnsDomainPtr& domain) {
- if (fqdn == "") {
+ if (fqdn.empty()) {
// This is a programmatic error and should not happen.
- isc_throw (D2CfgError, "matchReverse passed a null or empty fqdn");
+ isc_throw(D2CfgError, "matchReverse passed a null or empty fqdn");
}
// Fetch the reverse manager from the D2 context.
- DdnsDomainListMgrPtr& mgr = getD2CfgContext()->getReverseMgr();
+ DdnsDomainListMgrPtr mgr = getD2CfgContext()->getReverseMgr();
// Call the manager's match method and return the result.
return (mgr->matchDomain(fqdn, domain));
@@ -99,10 +110,14 @@ D2CfgMgr::createConfigParser(const std::string& config_id) {
parser = new Uint32Parser(config_id, context->getUint32Storage());
} else if (config_id == "forward_ddns") {
parser = new DdnsDomainListMgrParser("forward_mgr",
- context->getForwardMgr());
+ context->getForwardMgr(),
+ context->getKeys());
} else if (config_id == "reverse_ddns") {
parser = new DdnsDomainListMgrParser("reverse_mgr",
- context->getReverseMgr());
+ context->getReverseMgr(),
+ context->getKeys());
+ } else if (config_id == "tsig_keys") {
+ parser = new TSIGKeyInfoListParser("tsig_key_list", context->getKeys());
} else {
isc_throw(NotImplemented,
"parser error: D2CfgMgr parameter not supported: "
diff --git a/src/bin/d2/d2_cfg_mgr.h b/src/bin/d2/d2_cfg_mgr.h
index ed4a561..785c204 100644
--- a/src/bin/d2/d2_cfg_mgr.h
+++ b/src/bin/d2/d2_cfg_mgr.h
@@ -28,6 +28,7 @@ namespace isc {
namespace d2 {
/// @brief DHCP-DDNS Configuration Context
+///
/// Implements the storage container for configuration context.
/// It provides a single enclosure for the storage of configuration parameters
/// and any other DHCP-DDNS specific information that needs to be accessible
@@ -45,23 +46,30 @@ public:
///
/// @return returns a raw pointer to the new clone.
virtual D2CfgContext* clone() {
- return (new D2CfgContext(*this));
+ return (new D2CfgContext(*this));
}
/// @brief Fetches the forward DNS domain list manager.
///
- /// @return returns a pointer reference to the forward manager.
- DdnsDomainListMgrPtr& getForwardMgr() {
+ /// @return returns a pointer to the forward manager.
+ DdnsDomainListMgrPtr getForwardMgr() {
return (forward_mgr_);
}
/// @brief Fetches the reverse DNS domain list manager.
///
- /// @return returns a pointer reference to the reverse manager.
- DdnsDomainListMgrPtr& getReverseMgr() {
+ /// @return returns a pointer to the reverse manager.
+ DdnsDomainListMgrPtr getReverseMgr() {
return (reverse_mgr_);
}
+ /// @brief Fetches the map of TSIG keys.
+ ///
+ /// @return returns a pointer to the key map.
+ TSIGKeyInfoMapPtr getKeys() {
+ return (keys_);
+ }
+
protected:
/// @brief Copy constructor for use by derivations in clone().
D2CfgContext(const D2CfgContext& rhs);
@@ -75,6 +83,9 @@ private:
/// @brief Reverse domain list manager.
DdnsDomainListMgrPtr reverse_mgr_;
+
+ /// @brief Storage for the map of TSIGKeyInfos
+ TSIGKeyInfoMapPtr keys_;
};
/// @brief Defines a pointer for DdnsDomain instances.
diff --git a/src/bin/d2/d2_config.cc b/src/bin/d2/d2_config.cc
index 49448ac..24c8f49 100644
--- a/src/bin/d2/d2_config.cc
+++ b/src/bin/d2/d2_config.cc
@@ -24,16 +24,25 @@
namespace isc {
namespace d2 {
-// *********************** DnsServerInfo *************************
+// *********************** TSIGKeyInfo *************************
+
+TSIGKeyInfo::TSIGKeyInfo(const std::string& name, const std::string& algorithm,
+ const std::string& secret)
+ :name_(name), algorithm_(algorithm), secret_(secret) {
+}
+
+TSIGKeyInfo::~TSIGKeyInfo() {
+}
-const uint32_t DnsServerInfo::standard_dns_port = 53;
-const char* DnsServerInfo::empty_ip_str = "0.0.0.0";
+// *********************** DnsServerInfo *************************
-DnsServerInfo::DnsServerInfo(const std::string& hostname,
+const char* DnsServerInfo::EMPTY_IP_STR = "0.0.0.0";
+
+DnsServerInfo::DnsServerInfo(const std::string& hostname,
isc::asiolink::IOAddress ip_address, uint32_t port,
bool enabled)
- :hostname_(hostname), ip_address_(ip_address), port_(port),
+ :hostname_(hostname), ip_address_(ip_address), port_(port),
enabled_(enabled) {
}
@@ -52,35 +61,31 @@ DdnsDomain::~DdnsDomain() {
// *********************** DdnsDomainLstMgr *************************
+const char* DdnsDomainListMgr::wildcard_domain_name_ = "*";
+
DdnsDomainListMgr::DdnsDomainListMgr(const std::string& name) : name_(name),
- domains_(new DdnsDomainStorage()) {
+ domains_(new DdnsDomainMap()) {
}
DdnsDomainListMgr::~DdnsDomainListMgr () {
}
-void
-DdnsDomainListMgr::setDomains(DdnsDomainStoragePtr domains) {
+void
+DdnsDomainListMgr::setDomains(DdnsDomainMapPtr domains) {
if (!domains) {
- isc_throw(D2CfgError,
+ isc_throw(D2CfgError,
"DdnsDomainListMgr::setDomains: Domain list may not be null");
}
domains_ = domains;
- // Iterate over the domain list lookfing for the wild card domain. If
- // present, set the member variable to remember it. This saves us from
- // having to look for it every time we match.
- DdnsDomainPtrPair domain_pair;
- BOOST_FOREACH(domain_pair, (*domains_)) {
- DdnsDomainPtr domain = domain_pair.second;
- const std::string& domain_name = domain->getName();
-
- if (domain_name == "*") {
- wildcard_domain_ = domain;
- break;
- }
+ // Look for the wild card domain. If present, set the member variable
+ // to remember it. This saves us from having to look for it every time
+ // we attempt a match.
+ DdnsDomainMap::iterator gotit = domains_->find(wildcard_domain_name_);
+ if (gotit != domains_->end()) {
+ wildcard_domain_ = gotit->second;
}
}
@@ -96,48 +101,181 @@ DdnsDomainListMgr::matchDomain(const std::string& fqdn, DdnsDomainPtr& domain) {
}
// Start with the longest version of the fqdn and search the list.
- // Continue looking for shorter versions of fqdn so long as no match is
+ // Continue looking for shorter versions of fqdn so long as no match is
// found.
- // @TODO This can surely be optimized, time permitting.
+ // @TODO This can surely be optimized, time permitting.
std::string match_name = fqdn;
std::size_t start_pos = 0;
while (start_pos != std::string::npos) {
match_name = match_name.substr(start_pos, std::string::npos);
- DdnsDomainStorage::iterator gotit = domains_->find(match_name);
+ DdnsDomainMap::iterator gotit = domains_->find(match_name);
if (gotit != domains_->end()) {
domain = gotit->second;
- break;
+ return (true);
}
start_pos = match_name.find_first_of(".");
if (start_pos != std::string::npos) {
- start_pos++;
+ ++start_pos;
}
}
- if (!domain) {
- // There's no match. If they specified a wild card domain use it
- // otherwise there's no domain for this entry.
- if (wildcard_domain_) {
- domain = wildcard_domain_;
- } else {
- LOG_WARN(dctl_logger, DHCP_DDNS_NO_MATCH).arg(fqdn);
- return (false);
- }
- }
+ // There's no match. If they specified a wild card domain use it
+ // otherwise there's no domain for this entry.
+ if (wildcard_domain_) {
+ domain = wildcard_domain_;
+ return (true);
+ }
- return (true);
+ LOG_WARN(dctl_logger, DHCP_DDNS_NO_MATCH).arg(fqdn);
+ return (false);
}
// *************************** PARSERS ***********************************
+// *********************** TSIGKeyInfoParser *************************
+
+TSIGKeyInfoParser::TSIGKeyInfoParser(const std::string& entry_name,
+ TSIGKeyInfoMapPtr keys)
+ : entry_name_(entry_name), keys_(keys), local_scalars_() {
+ if (!keys_) {
+ isc_throw(D2CfgError, "TSIGKeyInfoParser ctor:"
+ " key storage cannot be null");
+ }
+}
+
+TSIGKeyInfoParser::~TSIGKeyInfoParser() {
+}
+
+void
+TSIGKeyInfoParser::build(isc::data::ConstElementPtr key_config) {
+ isc::dhcp::ConfigPair config_pair;
+ // For each element in the key configuration:
+ // 1. Create a parser for the element.
+ // 2. Invoke the parser's build method passing in the element's
+ // configuration.
+ // 3. Invoke the parser's commit method to store the element's parsed
+ // data to the parser's local storage.
+ BOOST_FOREACH (config_pair, key_config->mapValue()) {
+ isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first));
+ parser->build(config_pair.second);
+ parser->commit();
+ }
+}
+
+isc::dhcp::ParserPtr
+TSIGKeyInfoParser::createConfigParser(const std::string& config_id) {
+ DhcpConfigParser* parser = NULL;
+ // Based on the configuration id of the element, create the appropriate
+ // parser. Scalars are set to use the parser's local scalar storage.
+ if ((config_id == "name") ||
+ (config_id == "algorithm") ||
+ (config_id == "secret")) {
+ parser = new isc::dhcp::StringParser(config_id,
+ local_scalars_.getStringStorage());
+ } else {
+ isc_throw(NotImplemented,
+ "parser error: TSIGKeyInfo parameter not supported: "
+ << config_id);
+ }
+
+ // Return the new parser instance.
+ return (isc::dhcp::ParserPtr(parser));
+}
+
+void
+TSIGKeyInfoParser::commit() {
+ std::string name;
+ std::string algorithm;
+ std::string secret;
+
+ // Fetch the key configuration's parsed scalar values from parser's
+ // local storage.
+ local_scalars_.getParam("name", name);
+ local_scalars_.getParam("algorithm", algorithm);
+ local_scalars_.getParam("secret", secret);
+
+ // @TODO Validation here is very superficial. This will expand as TSIG
+ // Key use is more fully implemented.
+
+ // Name cannot be blank.
+ if (name.empty()) {
+ isc_throw(D2CfgError, "TSIG Key Info must specify name");
+ }
+
+ // Algorithme cannot be blank.
+ if (algorithm.empty()) {
+ isc_throw(D2CfgError, "TSIG Key Info must specify algorithm");
+ }
+
+ // Secret cannot be blank.
+ if (secret.empty()) {
+ isc_throw(D2CfgError, "TSIG Key Info must specify secret");
+ }
+
+ // Currently, the premise is that key storage is always empty prior to
+ // parsing so we are always adding keys never replacing them. Duplicates
+ // are not allowed and should be flagged as a configuration error.
+ if (keys_->find(name) != keys_->end()) {
+ isc_throw(D2CfgError, "Duplicate TSIG key specified:" << name);
+ }
+
+ TSIGKeyInfoPtr key_info(new TSIGKeyInfo(name, algorithm, secret));
+
+ // Add the new TSIGKeyInfo to the key storage.
+ (*keys_)[name]=key_info;
+}
+
+// *********************** TSIGKeyInfoListParser *************************
+
+TSIGKeyInfoListParser::TSIGKeyInfoListParser(const std::string& list_name,
+ TSIGKeyInfoMapPtr keys)
+ :list_name_(list_name), keys_(keys), parsers_() {
+ if (!keys_) {
+ isc_throw(D2CfgError, "TSIGKeyInfoListParser ctor:"
+ " key storage cannot be null");
+ }
+}
+
+TSIGKeyInfoListParser::~TSIGKeyInfoListParser(){
+}
+
+void
+TSIGKeyInfoListParser::
+build(isc::data::ConstElementPtr key_list){
+ int i = 0;
+ isc::data::ConstElementPtr key_config;
+ // For each key element in the key list:
+ // 1. Create a parser for the key element.
+ // 2. Invoke the parser's build method passing in the key's
+ // configuration.
+ // 3. Add the parser to a local collection of parsers.
+ BOOST_FOREACH(key_config, key_list->listValue()) {
+ // Create a name for the parser based on its position in the list.
+ std::string entry_name = boost::lexical_cast<std::string>(i++);
+ isc::dhcp::ParserPtr parser(new TSIGKeyInfoParser(entry_name,
+ keys_));
+ parser->build(key_config);
+ parsers_.push_back(parser);
+ }
+}
+
+void
+TSIGKeyInfoListParser::commit() {
+ // Invoke commit on each server parser. This will cause each one to
+ // create it's server instance and commit it to storage.
+ BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
+ parser->commit();
+ }
+}
+
// *********************** DnsServerInfoParser *************************
DnsServerInfoParser::DnsServerInfoParser(const std::string& entry_name,
- DnsServerInfoStoragePtr servers)
+ DnsServerInfoStoragePtr servers)
: entry_name_(entry_name), servers_(servers), local_scalars_() {
if (!servers_) {
- isc_throw(D2CfgError, "DdnsServerInfoParser ctor:"
+ isc_throw(D2CfgError, "DnsServerInfoParser ctor:"
" server storage cannot be null");
}
}
@@ -145,12 +283,12 @@ DnsServerInfoParser::DnsServerInfoParser(const std::string& entry_name,
DnsServerInfoParser::~DnsServerInfoParser() {
}
-void
+void
DnsServerInfoParser::build(isc::data::ConstElementPtr server_config) {
isc::dhcp::ConfigPair config_pair;
// For each element in the server configuration:
// 1. Create a parser for the element.
- // 2. Invoke the parser's build method passing in the element's
+ // 2. Invoke the parser's build method passing in the element's
// configuration.
// 3. Invoke the parser's commit method to store the element's parsed
// data to the parser's local storage.
@@ -159,24 +297,24 @@ DnsServerInfoParser::build(isc::data::ConstElementPtr server_config) {
parser->build(config_pair.second);
parser->commit();
}
-
+
}
-isc::dhcp::ParserPtr
+isc::dhcp::ParserPtr
DnsServerInfoParser::createConfigParser(const std::string& config_id) {
DhcpConfigParser* parser = NULL;
// Based on the configuration id of the element, create the appropriate
- // parser. Scalars are set to use the parser's local scalar storage.
+ // parser. Scalars are set to use the parser's local scalar storage.
if ((config_id == "hostname") ||
(config_id == "ip_address")) {
- parser = new isc::dhcp::StringParser(config_id,
+ parser = new isc::dhcp::StringParser(config_id,
local_scalars_.getStringStorage());
- } else if (config_id == "port") {
- parser = new isc::dhcp::Uint32Parser(config_id,
+ } else if (config_id == "port") {
+ parser = new isc::dhcp::Uint32Parser(config_id,
local_scalars_.getUint32Storage());
} else {
- isc_throw(NotImplemented,
- "parser error: DnsServerInfo parameter not supported: "
+ isc_throw(NotImplemented,
+ "parser error: DnsServerInfo parameter not supported: "
<< config_id);
}
@@ -184,50 +322,44 @@ DnsServerInfoParser::createConfigParser(const std::string& config_id) {
return (isc::dhcp::ParserPtr(parser));
}
-void
+void
DnsServerInfoParser::commit() {
std::string hostname;
std::string ip_address;
- uint32_t port = DnsServerInfo::standard_dns_port;
+ uint32_t port = DnsServerInfo::STANDARD_DNS_PORT;
- // Fetch the server configuration's paresed scalar values from parser's
- // local storage.
- local_scalars_.getParam("hostname", hostname, DCfgContextBase::optional_);
- local_scalars_.getParam("ip_address", ip_address,
- DCfgContextBase::optional_);
- local_scalars_.getParam("port", port, DCfgContextBase::optional_);
-
- // The configuration cannot specify both hostname and ip_address.
- if ((hostname != "") && (ip_address != "")) {
- isc_throw(D2CfgError,
- "Dns Server cannot specify both hostname and static IP address");
- }
+ // Fetch the server configuration's parsed scalar values from parser's
+ // local storage.
+ local_scalars_.getParam("hostname", hostname, DCfgContextBase::OPTIONAL);
+ local_scalars_.getParam("ip_address", ip_address,
+ DCfgContextBase::OPTIONAL);
+ local_scalars_.getParam("port", port, DCfgContextBase::OPTIONAL);
// The configuration must specify one or the other.
- if ((hostname == "") && (ip_address == "")) {
- isc_throw(D2CfgError,
- "Dns Server must specify either hostname or static IP address");
+ if (hostname.empty() == ip_address.empty()) {
+ isc_throw(D2CfgError, "Dns Server must specify one or the other"
+ " of hostname and IP address");
}
- DnsServerInfo* serverInfo = NULL;
- if (hostname != "") {
+ DnsServerInfoPtr serverInfo;
+ if (!hostname.empty()) {
// When hostname is specified, create a valid, blank IOAddress and
// then create the DnsServerInfo.
- isc::asiolink::IOAddress io_addr(DnsServerInfo::empty_ip_str);
- serverInfo = new DnsServerInfo(hostname, io_addr, port);
+ isc::asiolink::IOAddress io_addr(DnsServerInfo::EMPTY_IP_STR);
+ serverInfo.reset(new DnsServerInfo(hostname, io_addr, port));
} else {
try {
// Create an IOAddress from the IP address string given and then
// create the DnsServerInfo.
isc::asiolink::IOAddress io_addr(ip_address);
- serverInfo = new DnsServerInfo(hostname, io_addr, port);
+ serverInfo.reset(new DnsServerInfo(hostname, io_addr, port));
} catch (const isc::asiolink::IOError& ex) {
isc_throw(D2CfgError, "Invalid IP address:" << ip_address);
}
}
// Add the new DnsServerInfo to the server storage.
- servers_->push_back(DnsServerInfoPtr(serverInfo));
+ servers_->push_back(serverInfo);
}
// *********************** DnsServerInfoListParser *************************
@@ -244,27 +376,27 @@ DnsServerInfoListParser::DnsServerInfoListParser(const std::string& list_name,
DnsServerInfoListParser::~DnsServerInfoListParser(){
}
-void
+void
DnsServerInfoListParser::
build(isc::data::ConstElementPtr server_list){
int i = 0;
isc::data::ConstElementPtr server_config;
- // For each server element in the server list:
+ // For each server element in the server list:
// 1. Create a parser for the server element.
- // 2. Invoke the parser's build method passing in the server's
+ // 2. Invoke the parser's build method passing in the server's
// configuration.
// 3. Add the parser to a local collection of parsers.
BOOST_FOREACH(server_config, server_list->listValue()) {
// Create a name for the parser based on its position in the list.
std::string entry_name = boost::lexical_cast<std::string>(i++);
- isc::dhcp::ParserPtr parser(new DnsServerInfoParser(entry_name,
+ isc::dhcp::ParserPtr parser(new DnsServerInfoParser(entry_name,
servers_));
parser->build(server_config);
parsers_.push_back(parser);
}
}
-void
+void
DnsServerInfoListParser::commit() {
// Domains must have at least one server.
if (parsers_.size() == 0) {
@@ -272,7 +404,7 @@ DnsServerInfoListParser::commit() {
}
// Invoke commit on each server parser. This will cause each one to
- // create it's server instance and commit it to storage.
+ // create it's server instance and commit it to storage.
BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
parser->commit();
}
@@ -281,11 +413,12 @@ DnsServerInfoListParser::commit() {
// *********************** DdnsDomainParser *************************
DdnsDomainParser::DdnsDomainParser(const std::string& entry_name,
- DdnsDomainStoragePtr domains)
- : entry_name_(entry_name), domains_(domains),
+ DdnsDomainMapPtr domains,
+ TSIGKeyInfoMapPtr keys)
+ : entry_name_(entry_name), domains_(domains), keys_(keys),
local_servers_(new DnsServerInfoStorage()), local_scalars_() {
if (!domains_) {
- isc_throw(D2CfgError,
+ isc_throw(D2CfgError,
"DdnsDomainParser ctor, domain storage cannot be null");
}
}
@@ -294,11 +427,11 @@ DdnsDomainParser::DdnsDomainParser(const std::string& entry_name,
DdnsDomainParser::~DdnsDomainParser() {
}
-void
+void
DdnsDomainParser::build(isc::data::ConstElementPtr domain_config) {
// For each element in the domain configuration:
// 1. Create a parser for the element.
- // 2. Invoke the parser's build method passing in the element's
+ // 2. Invoke the parser's build method passing in the element's
// configuration.
// 3. Invoke the parser's commit method to store the element's parsed
// data to the parser's local storage.
@@ -310,14 +443,14 @@ DdnsDomainParser::build(isc::data::ConstElementPtr domain_config) {
}
}
-isc::dhcp::ParserPtr
+isc::dhcp::ParserPtr
DdnsDomainParser::createConfigParser(const std::string& config_id) {
DhcpConfigParser* parser = NULL;
// Based on the configuration id of the element, create the appropriate
- // parser. Scalars are set to use the parser's local scalar storage.
+ // parser. Scalars are set to use the parser's local scalar storage.
if ((config_id == "name") ||
- (config_id == "key_name")) {
- parser = new isc::dhcp::StringParser(config_id,
+ (config_id == "key_name")) {
+ parser = new isc::dhcp::StringParser(config_id,
local_scalars_.getStringStorage());
} else if (config_id == "dns_servers") {
// Server list parser is given in our local server storage. It will pass
@@ -326,7 +459,7 @@ DdnsDomainParser::createConfigParser(const std::string& config_id) {
parser = new DnsServerInfoListParser(config_id, local_servers_);
} else {
isc_throw(NotImplemented,
- "parser error: DdnsDomain parameter not supported: "
+ "parser error: DdnsDomain parameter not supported: "
<< config_id);
}
@@ -334,16 +467,16 @@ DdnsDomainParser::createConfigParser(const std::string& config_id) {
return (isc::dhcp::ParserPtr(parser));
}
-void
+void
DdnsDomainParser::commit() {
std::string name;
std::string key_name;
// Domain name is not optional. The get will throw if its not there.
- local_scalars_.getParam("name", name);
+ local_scalars_.getParam("name", name);
// Blank domain names are not allowed.
- if (name == "") {
+ if (name.empty()) {
isc_throw(D2CfgError, "Domain name cannot be blank");
}
@@ -352,12 +485,18 @@ DdnsDomainParser::commit() {
// Duplicates are not allowed and should be flagged as a configuration
// error.
if (domains_->find(name) != domains_->end()) {
- isc_throw(D2CfgError, "Duplicate domain specified:" << name);
+ isc_throw(D2CfgError, "Duplicate domain specified:" << name);
}
- // Key name is optional and for now, unused. It is intended to be
- // used as the name of the TSIG key this domain should use.
- local_scalars_.getParam("key_name", key_name, DCfgContextBase::optional_);
+ // Key name is optional. If it is not blank, then validate it against
+ // the defined list of keys.
+ local_scalars_.getParam("key_name", key_name, DCfgContextBase::OPTIONAL);
+ if (!key_name.empty()) {
+ if ((!keys_) || (keys_->find(key_name) == keys_->end())) {
+ isc_throw(D2CfgError, "DdnsDomain :" << name <<
+ " specifies and undefined key:" << key_name);
+ }
+ }
// Instantiate the new domain and add it to domain storage.
DdnsDomainPtr domain(new DdnsDomain(name, key_name, local_servers_));
@@ -369,8 +508,9 @@ DdnsDomainParser::commit() {
// *********************** DdnsDomainListParser *************************
DdnsDomainListParser::DdnsDomainListParser(const std::string& list_name,
- DdnsDomainStoragePtr domains)
- :list_name_(list_name), domains_(domains), parsers_() {
+ DdnsDomainMapPtr domains,
+ TSIGKeyInfoMapPtr keys)
+ :list_name_(list_name), domains_(domains), keys_(keys), parsers_() {
if (!domains_) {
isc_throw(D2CfgError, "DdnsDomainListParser ctor:"
" domain storage cannot be null");
@@ -380,28 +520,29 @@ DdnsDomainListParser::DdnsDomainListParser(const std::string& list_name,
DdnsDomainListParser::~DdnsDomainListParser(){
}
-void
+void
DdnsDomainListParser::
build(isc::data::ConstElementPtr domain_list){
- // For each domain element in the domain list:
+ // For each domain element in the domain list:
// 1. Create a parser for the domain element.
- // 2. Invoke the parser's build method passing in the domain's
+ // 2. Invoke the parser's build method passing in the domain's
// configuration.
// 3. Add the parser to the local collection of parsers.
int i = 0;
isc::data::ConstElementPtr domain_config;
BOOST_FOREACH(domain_config, domain_list->listValue()) {
std::string entry_name = boost::lexical_cast<std::string>(i++);
- isc::dhcp::ParserPtr parser(new DdnsDomainParser(entry_name, domains_));
+ isc::dhcp::ParserPtr parser(new DdnsDomainParser(entry_name,
+ domains_, keys_));
parser->build(domain_config);
parsers_.push_back(parser);
}
}
-void
+void
DdnsDomainListParser::commit() {
// Invoke commit on each server parser. This will cause each one to
- // create it's server instance and commit it to storage.
+ // create it's server instance and commit it to storage.
BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
parser->commit();
}
@@ -411,20 +552,20 @@ DdnsDomainListParser::commit() {
// *********************** DdnsDomainListMgrParser *************************
DdnsDomainListMgrParser::DdnsDomainListMgrParser(const std::string& entry_name,
- DdnsDomainListMgrPtr& mgr)
- : entry_name_(entry_name), mgr_(mgr),
- local_domains_(new DdnsDomainStorage()), local_scalars_() {
+ DdnsDomainListMgrPtr mgr, TSIGKeyInfoMapPtr keys)
+ : entry_name_(entry_name), mgr_(mgr), keys_(keys),
+ local_domains_(new DdnsDomainMap()), local_scalars_() {
}
DdnsDomainListMgrParser::~DdnsDomainListMgrParser() {
}
-void
+void
DdnsDomainListMgrParser::build(isc::data::ConstElementPtr domain_config) {
// For each element in the domain manager configuration:
// 1. Create a parser for the element.
- // 2. Invoke the parser's build method passing in the element's
+ // 2. Invoke the parser's build method passing in the element's
// configuration.
// 3. Invoke the parser's commit method to store the element's parsed
// data to the parser's local storage.
@@ -436,14 +577,14 @@ DdnsDomainListMgrParser::build(isc::data::ConstElementPtr domain_config) {
}
}
-isc::dhcp::ParserPtr
+isc::dhcp::ParserPtr
DdnsDomainListMgrParser::createConfigParser(const std::string& config_id) {
DhcpConfigParser* parser = NULL;
if (config_id == "ddns_domains") {
// Domain list parser is given our local domain storage. It will pass
// this down to its domain parsers and is where they will write their
// domain instances upon commit.
- parser = new DdnsDomainListParser(config_id, local_domains_);
+ parser = new DdnsDomainListParser(config_id, local_domains_, keys_);
} else {
isc_throw(NotImplemented, "parser error: "
"DdnsDomainListMgr parameter not supported: " << config_id);
@@ -453,13 +594,12 @@ DdnsDomainListMgrParser::createConfigParser(const std::string& config_id) {
return (isc::dhcp::ParserPtr(parser));
}
-void
+void
DdnsDomainListMgrParser::commit() {
// Add the new domain to the domain storage.
mgr_->setDomains(local_domains_);
}
-
}; // end of isc::dhcp namespace
}; // end of isc namespace
diff --git a/src/bin/d2/d2_config.h b/src/bin/d2/d2_config.h
index d07a54c..f53d1e2 100644
--- a/src/bin/d2/d2_config.h
+++ b/src/bin/d2/d2_config.h
@@ -35,16 +35,25 @@ namespace d2 {
///
/// This file contains the class declarations for the class hierarchy created
/// from the D2 configuration and the parser classes used to create it.
-/// The application configuration consists of a set of scalar parameters and
-/// two managed lists of domains: one list for forward domains and one list for
-/// reverse domains.
+/// The application configuration consists of a set of scalar parameters,
+/// a list of TSIG keys, and two managed lists of domains: one list for
+/// forward domains and one list for reverse domains.
///
-/// Each managed list consists of a list one or more domains and is represented
-/// by the class DdnsDomainListMgr.
+/// The key list consists of one or more TSIG keys, each entry described by
+/// a name, the algorithm method name, and its secret key component.
+///
+/// @TODO NOTE that TSIG configuration parsing is functional, the use of
+/// TSIG Keys during the actual DNS update transactions is not. This will be
+/// implemented in a future release.
+///
+/// Each managed domain list consists of a list one or more domains and is
+/// represented by the class DdnsDomainListMgr.
///
/// Each domain consists of a set of scalars parameters and a list of DNS
-/// servers which support that domain. Domains are represented by the class,
-/// DdnsDomain.
+/// servers which support that domain. Among its scalars, is key_name, which
+/// is the name of the TSIG Key to use for with this domain. This value should
+/// map to one of the TSIG Keys in the key list. Domains are represented by
+/// the class, DdnsDomain.
///
/// Each server consists of a set of scalars used to describe the server such
/// that the application can carry out DNS update exchanges with it. Servers
@@ -70,6 +79,61 @@ namespace d2 {
/// each server entry in its list.
///
/// A DdnsServerInfoParser handles the scalars which belong to the server.
+/// The following is sample configuration in JSON form with extra spacing
+/// for clarity:
+///
+/// @code
+/// {
+/// "interface" : "eth1" ,
+/// "ip_address" : "192.168.1.33" ,
+/// "port" : 88 ,
+/// "tsig_keys":
+//// [
+/// {
+/// "name": "d2_key.tmark.org" ,
+/// "algorithm": "md5" ,
+/// "secret": "0123456989"
+/// }
+/// ],
+/// "forward_ddns" :
+/// {
+/// "ddns_domains":
+/// [
+/// {
+/// "name": "tmark.org." ,
+/// "key_name": "d2_key.tmark.org" ,
+/// "dns_servers" :
+/// [
+/// { "hostname": "fserver.tmark.org" },
+/// { "hostname": "f2server.tmark.org" }
+/// ]
+/// },
+/// {
+/// "name": "pub.tmark.org." ,
+/// "key_name": "d2_key.tmark.org" ,
+/// "dns_servers" :
+/// [
+/// { "hostname": "f3server.tmark.org" }
+/// ]
+/// }
+/// ]
+/// },
+/// "reverse_ddns" :
+/// {
+/// "ddns_domains":
+/// [
+/// {
+/// "name": " 0.168.192.in.addr.arpa." ,
+/// "key_name": "d2_key.tmark.org" ,
+/// "dns_servers" :
+/// [
+/// { "ip_address": "127.0.0.101" , "port": 100 }
+/// ]
+/// }
+/// ]
+/// }
+/// }
+/// @endcode
/// @brief Exception thrown when the error during configuration handling
/// occurs.
@@ -79,6 +143,77 @@ public:
isc::Exception(file, line, what) { };
};
+/// @brief Represents a TSIG Key.
+///
+/// Currently, this is simple storage class containing the basic attributes of
+/// a TSIG Key. It is intended primarily as a reference for working with
+/// actual keys and may eventually be replaced by isc::dns::TSIGKey. TSIG Key
+/// functionality at this stage is strictly limited to configuration parsing.
+/// @TODO full functionality for using TSIG during DNS updates will be added
+/// in a future release.
+class TSIGKeyInfo {
+public:
+
+ /// @brief Constructor
+ ///
+ /// @param name the unique label used to identify this key
+ /// @param algorithm the name of the encryption alogirthm this key uses.
+ /// (@TODO This will be a fixed list of choices)
+ /// @param secret the secret component of this key
+ TSIGKeyInfo(const std::string& name, const std::string& algorithm,
+ const std::string& secret);
+
+ /// @brief Destructor
+ virtual ~TSIGKeyInfo();
+
+ /// @brief Getter which returns the key's name.
+ ///
+ /// @return returns the name as as std::string.
+ const std::string getName() const {
+ return (name_);
+ }
+
+ /// @brief Getter which returns the key's algorithm.
+ ///
+ /// @return returns the algorithm as as std::string.
+ const std::string getAlgorithm() const {
+ return (algorithm_);
+ }
+
+ /// @brief Getter which returns the key's secret.
+ ///
+ /// @return returns the secret as as std::string.
+ const std::string getSecret() const {
+ return (secret_);
+ }
+
+private:
+ /// @brief The name of the key.
+ ///
+ /// This value is the unique identifeir thay domains use to
+ /// to specify which TSIG key they need.
+ std::string name_;
+
+ /// @brief The algorithm that should be used for this key.
+ std::string algorithm_;
+
+ /// @brief The secret value component of this key.
+ std::string secret_;
+};
+
+/// @brief Defines a pointer for TSIGKeyInfo instances.
+typedef boost::shared_ptr<TSIGKeyInfo> TSIGKeyInfoPtr;
+
+/// @brief Defines a map of TSIGKeyInfos, keyed by the name.
+typedef std::map<std::string, TSIGKeyInfoPtr> TSIGKeyInfoMap;
+
+/// @brief Defines a iterator pairing of name and TSIGKeyInfo
+typedef std::pair<std::string, TSIGKeyInfoPtr> TSIGKeyInfoMapPair;
+
+/// @brief Defines a pointer to map of TSIGkeyInfos
+typedef boost::shared_ptr<TSIGKeyInfoMap> TSIGKeyInfoMapPtr;
+
+
/// @brief Represents a specific DNS Server.
/// It provides information about the server's network identity and typically
/// belongs to a list of servers supporting DNS for a given domain. It will
@@ -88,10 +223,11 @@ class DnsServerInfo {
public:
/// @brief defines DNS standard port value
- static const uint32_t standard_dns_port;
+ static const uint32_t STANDARD_DNS_PORT = 53;
/// @brief defines an "empty" string version of an ip address.
- static const char* empty_ip_str;
+ static const char* EMPTY_IP_STR;
+
/// @brief Constructor
///
@@ -106,7 +242,8 @@ public:
/// @param enabled is a flag that indicates whether this server is
/// enabled for use. It defaults to true.
DnsServerInfo(const std::string& hostname,
- isc::asiolink::IOAddress ip_address, uint32_t port,
+ isc::asiolink::IOAddress ip_address,
+ uint32_t port=STANDARD_DNS_PORT,
bool enabled=true);
/// @brief Destructor
@@ -189,7 +326,6 @@ public:
///
/// @param name is the domain name of the domain.
/// @param key_name is the TSIG key name for use with this domain.
- /// (@TODO TSIG is not yet functional).
/// @param servers is the list of server(s) supporting this domain.
DdnsDomain(const std::string& name, const std::string& key_name,
DnsServerInfoStoragePtr servers);
@@ -223,7 +359,6 @@ private:
std::string name_;
/// @brief The name of the TSIG key for use with this domain.
- /// @TODO TSIG is not yet functional).
std::string key_name_;
/// @brief The list of server(s) supporting this domain.
@@ -233,15 +368,14 @@ private:
/// @brief Defines a pointer for DdnsDomain instances.
typedef boost::shared_ptr<DdnsDomain> DdnsDomainPtr;
-/// @brief Defines a storage container for DdnsDomain pointers.
-typedef std::map<std::string, DdnsDomainPtr> DdnsDomainStorage;
-
-/// @brief Defines a pointer to DdnsDomain storage containers.
-typedef boost::shared_ptr<DdnsDomainStorage> DdnsDomainStoragePtr;
+/// @brief Defines a map of DdnsDomains, keyed by the domain name.
+typedef std::map<std::string, DdnsDomainPtr> DdnsDomainMap;
-/// @brief Defines a domain and domain key pair for iterating.
-typedef std::pair<std::string, DdnsDomainPtr> DdnsDomainPtrPair;
+/// @brief Defines a iterator pairing domain name and DdnsDomain
+typedef std::pair<std::string, DdnsDomainPtr> DdnsDomainMapPair;
+/// @brief Defines a pointer to DdnsDomain storage containers.
+typedef boost::shared_ptr<DdnsDomainMap> DdnsDomainMapPtr;
/// @brief Provides storage for and management of a list of DNS domains.
/// In addition to housing the domain list storage, it provides domain matching
@@ -252,6 +386,9 @@ typedef std::pair<std::string, DdnsDomainPtr> DdnsDomainPtrPair;
/// As matching capabilities evolve this class is expected to expand.
class DdnsDomainListMgr {
public:
+ /// @brief defines the domain name for denoting the wildcard domain.
+ static const char* wildcard_domain_name_;
+
/// @brief Constructor
///
/// @param name is an arbitrary label assigned to this manager.
@@ -267,7 +404,7 @@ public:
/// sub-domain from the FQDN until a match is found. If no match is found
/// and the wild card domain is present in the list, then return it as the
/// match. If the wild card domain is the only domain in the list, then
- /// the it will be returned immediately for any FQDN.
+ /// it will be returned immediately for any FQDN.
///
/// @param fqdn is the name for which to look.
/// @param domain receives the matching domain. Note that it will be reset
@@ -301,21 +438,21 @@ public:
/// @brief Fetches the domain list.
///
/// @return returns a pointer reference to the list of domains.
- const DdnsDomainStoragePtr &getDomains() {
+ const DdnsDomainMapPtr &getDomains() {
return (domains_);
}
/// @brief Sets the manger's domain list to the given list of domains.
/// This method will scan the inbound list for the wild card domain and
/// set the internal wild card domain pointer accordingly.
- void setDomains(DdnsDomainStoragePtr domains);
+ void setDomains(DdnsDomainMapPtr domains);
private:
/// @brief An arbitrary label assigned to this manager.
std::string name_;
- /// @brief Storage for the list of domains.
- DdnsDomainStoragePtr domains_;
+ /// @brief Map of the domains, keyed by name.
+ DdnsDomainMapPtr domains_;
/// @brief Pointer to the wild card domain.
DdnsDomainPtr wildcard_domain_;
@@ -325,11 +462,15 @@ private:
typedef boost::shared_ptr<DdnsDomainListMgr> DdnsDomainListMgrPtr;
/// @brief Storage container for scalar configuration parameters.
+///
/// This class is useful for implementing parsers for more complex configuration
/// elements (e.g. those of item type "map"). It provides a convenient way to
-/// add storage to the parser for an arbitrary number and variety of simple
+/// add storage to the parser for an arbitrary number and variety of scalar
/// configuration items (e.g. ints, bools, strings...) without explicitly adding
/// storage for each individual type needed by the parser.
+///
+/// This class implements a concrete version of the base class by supplying a
+/// "clone" method.
class DScalarContext : public DCfgContextBase {
public:
@@ -350,7 +491,7 @@ public:
protected:
/// @brief Copy constructor
- DScalarContext(const DScalarContext& rhs) : DCfgContextBase(rhs){
+ DScalarContext(const DScalarContext& rhs) : DCfgContextBase(rhs) {
}
private:
@@ -358,6 +499,116 @@ private:
DScalarContext& operator=(const DScalarContext& rhs);
};
+/// @brief Parser for TSIGKeyInfo
+///
+/// This class parses the configuration element "tsig_key" defined in
+/// src/bin/d2/dhcp-ddns.spec and creates an instance of a TSIGKeyInfo.
+class TSIGKeyInfoParser : public isc::dhcp::DhcpConfigParser {
+public:
+ /// @brief Constructor
+ ///
+ /// @param entry_name is an arbitrary label assigned to this configuration
+ /// definition. Since servers are specified in a list this value is likely
+ /// be something akin to "key:0", set during parsing.
+ /// @param servers is a pointer to the storage area to which the parser
+ /// should commit the newly created TSIGKeyInfo instance.
+ TSIGKeyInfoParser(const std::string& entry_name, TSIGKeyInfoMapPtr keys);
+
+ /// @brief Destructor
+ virtual ~TSIGKeyInfoParser();
+
+ /// @brief Performs the actual parsing of the given "tsig_key" element.
+ ///
+ /// The results of the parsing are retained internally for use during
+ /// commit.
+ ///
+ /// @param key_config is the "tsig_key" configuration to parse
+ virtual void build(isc::data::ConstElementPtr key_config);
+
+ /// @brief Creates a parser for the given "tsig_key" member element id.
+ ///
+ /// The key elements currently supported are(see dhcp-ddns.spec):
+ /// 1. name
+ /// 2. algorithm
+ /// 3. secret
+ ///
+ /// @param config_id is the "item_name" for a specific member element of
+ /// the "tsig_key" specification.
+ ///
+ /// @return returns a pointer to newly created parser.
+ virtual isc::dhcp::ParserPtr createConfigParser(const std::string&
+ config_id);
+
+ /// @brief Instantiates a DnsServerInfo from internal data values
+ /// saves it to the storage area pointed to by servers_.
+ virtual void commit();
+
+private:
+ /// @brief Arbitrary label assigned to this parser instance.
+ /// Since servers are specified in a list this value is likely be something
+ /// akin to "key:0", set during parsing. Primarily here for diagnostics.
+ std::string entry_name_;
+
+ /// @brief Pointer to the storage area to which the parser should commit
+ /// the newly created TSIGKeyInfo instance. This is given to us as a
+ /// constructor argument by an upper level.
+ TSIGKeyInfoMapPtr keys_;
+
+ /// @brief Local storage area for scalar parameter values. Use to hold
+ /// data until time to commit.
+ DScalarContext local_scalars_;
+};
+
+/// @brief Parser for a list of TSIGKeyInfos
+///
+/// This class parses a list of "tsig_key" configuration elements.
+/// (see src/bin/d2/dhcp-ddns.spec). The TSIGKeyInfo instances are added
+/// to the given storage upon commit.
+class TSIGKeyInfoListParser : public isc::dhcp::DhcpConfigParser {
+public:
+
+ /// @brief Constructor
+ ///
+ /// @param list_name is an arbitrary label assigned to this parser instance.
+ /// @param keys is a pointer to the storage area to which the parser
+ /// should commit the newly created TSIGKeyInfo instance.
+ TSIGKeyInfoListParser(const std::string& list_name, TSIGKeyInfoMapPtr keys);
+
+ /// @brief Destructor
+ virtual ~TSIGKeyInfoListParser();
+
+ /// @brief Performs the parsing of the given list "tsig_key" elements.
+ ///
+ /// It iterates over each key entry in the list:
+ /// 1. Instantiate a TSIGKeyInfoParser for the entry
+ /// 2. Pass the element configuration to the parser's build method
+ /// 3. Add the parser instance to local storage
+ ///
+ /// The net effect is to parse all of the key entries in the list
+ /// prepping them for commit.
+ ///
+ /// @param key_list_config is the list of "tsig_key" elements to parse.
+ virtual void build(isc::data::ConstElementPtr key_list_config);
+
+ /// @brief Iterates over the internal list of TSIGKeyInfoParsers,
+ /// invoking commit on each. This causes each parser to instantiate a
+ /// TSIGKeyInfo from its internal data values and add that that key
+ /// instance to the storage area, keys_.
+ virtual void commit();
+
+private:
+ /// @brief Arbitrary label assigned to this parser instance.
+ std::string list_name_;
+
+ /// @brief Pointer to the storage area to which the parser should commit
+ /// the list of newly created TSIGKeyInfo instances. This is given to us
+ /// as a constructor argument by an upper level.
+ TSIGKeyInfoMapPtr keys_;
+
+ /// @brief Local storage of TSIGKeyInfoParser instances
+ isc::dhcp::ParserCollection parsers_;
+};
+
/// @brief Parser for DnsServerInfo
///
/// This class parses the configuration element "dns_server" defined in
@@ -389,7 +640,7 @@ public:
/// The server elements currently supported are(see dhcp-ddns.spec):
/// 1. hostname
/// 2. ip_address
- /// 3. port
+ /// 3. port
///
/// @param config_id is the "item_name" for a specific member element of
/// the "dns_server" specification.
@@ -481,9 +732,10 @@ public:
/// definition. Since domains are specified in a list this value is likely
/// be something akin to "forward_ddns:0", set during parsing.
/// @param domains is a pointer to the storage area to which the parser
+ /// @param keys is a pointer to a map of the defined TSIG keys.
/// should commit the newly created DdnsDomain instance.
- DdnsDomainParser(const std::string& entry_name,
- DdnsDomainStoragePtr domains);
+ DdnsDomainParser(const std::string& entry_name, DdnsDomainMapPtr domains,
+ TSIGKeyInfoMapPtr keys);
/// @brief Destructor
virtual ~DdnsDomainParser();
@@ -521,7 +773,13 @@ private:
/// @brief Pointer to the storage area to which the parser should commit
/// the newly created DdnsDomain instance. This is given to us as a
/// constructor argument by an upper level.
- DdnsDomainStoragePtr domains_;
+ DdnsDomainMapPtr domains_;
+
+ /// @brief Pointer to the map of defined TSIG keys.
+ /// This map is passed into us and contains all of the TSIG keys defined
+ /// for this configuration. It is used to validate the key name entry of
+ /// DdnsDomains that specify one.
+ TSIGKeyInfoMapPtr keys_;
/// @brief Local storage for DnsServerInfo instances. This is passed into
/// DnsServerInfoListParser(s), which in turn passes it into each
@@ -546,9 +804,10 @@ public:
///
/// @param list_name is an arbitrary label assigned to this parser instance.
/// @param domains is a pointer to the storage area to which the parser
+ /// @param keys is a pointer to a map of the defined TSIG keys.
/// should commit the newly created DdnsDomain instance.
DdnsDomainListParser(const std::string& list_name,
- DdnsDomainStoragePtr domains_);
+ DdnsDomainMapPtr domains_, TSIGKeyInfoMapPtr keys);
/// @brief Destructor
virtual ~DdnsDomainListParser();
@@ -580,7 +839,13 @@ private:
/// @brief Pointer to the storage area to which the parser should commit
/// the list of newly created DdnsDomain instances. This is given to us
/// as a constructor argument by an upper level.
- DdnsDomainStoragePtr domains_;
+ DdnsDomainMapPtr domains_;
+
+ /// @brief Pointer to the map of defined TSIG keys.
+ /// This map is passed into us and contains all of the TSIG keys defined
+ /// for this configuration. It is used to validate the key name entry of
+ /// DdnsDomains that specify one.
+ TSIGKeyInfoMapPtr keys_;
/// @brief Local storage of DdnsDomainParser instances
isc::dhcp::ParserCollection parsers_;
@@ -600,9 +865,10 @@ public:
/// @param entry_name is an arbitrary label assigned to this configuration
/// definition.
/// @param mgr is a pointer to the DdnsDomainListMgr to populate.
+ /// @param keys is a pointer to a map of the defined TSIG keys.
/// @throw throws D2CfgError if mgr pointer is empty.
DdnsDomainListMgrParser(const std::string& entry_name,
- DdnsDomainListMgrPtr& mgr);
+ DdnsDomainListMgrPtr mgr, TSIGKeyInfoMapPtr keys);
/// @brief Destructor
virtual ~DdnsDomainListMgrParser();
@@ -616,9 +882,8 @@ public:
/// @brief Creates a parser for the given manager member element id.
///
- ///
/// The manager elements currently supported are (see dhcp-ddns.spec):
- /// 1. ddns_domains
+ /// 1. ddns_domains
///
/// @param config_id is the "item_name" for a specific member element of
/// the manager specification.
@@ -640,11 +905,17 @@ private:
/// upper level.
DdnsDomainListMgrPtr mgr_;
+ /// @brief Pointer to the map of defined TSIG keys.
+ /// This map is passed into us and contains all of the TSIG keys defined
+ /// for this configuration. It is used to validate the key name entry of
+ /// DdnsDomains that specify one.
+ TSIGKeyInfoMapPtr keys_;
+
/// @brief Local storage for DdnsDomain instances. This is passed into a
/// DdnsDomainListParser(s), which in turn passes it into each
/// DdnsDomainParser. When the DdnsDomainParsers "commit" they add their
/// domain instance to this storage.
- DdnsDomainStoragePtr local_domains_;
+ DdnsDomainMapPtr local_domains_;
/// @brief Local storage area for scalar parameter values. Use to hold
/// data until time to commit.
@@ -654,7 +925,6 @@ private:
};
-
}; // end of isc::d2 namespace
}; // end of isc namespace
diff --git a/src/bin/d2/d2_messages.mes b/src/bin/d2/d2_messages.mes
index ab12bfd..46df1aa 100644
--- a/src/bin/d2/d2_messages.mes
+++ b/src/bin/d2/d2_messages.mes
@@ -68,10 +68,14 @@ application and will exit.
A warning message is issued when an attempt is made to shut down the
application when it is not running.
-% DCTL_ORDER_ERROR Configuration contains more elements than the parsing order
-A debug message which indicates that configuration being parsed includes
-element ids not specified the configuration manager's parse order list. This is
-programming logic error.
+% DCTL_ORDER_ERROR configuration contains more elements than the parsing order
+An error message which indicates that configuration being parsed includes
+element ids not specified the configuration manager's parse order list. This
+is a programmatic error.
+
+% DCTL_ORDER_NO_ELEMENT element: %1 is in the parsing order but is missing from the configuration
+An error message indicating that the listed element is in specified in the
+parsing order but is not in the configuration. The configuration is incorrect.
% DCTL_PARSER_FAIL configuration parsing failed for configuration element: %1
On receipt of message containing details to a change of its configuration,
@@ -121,8 +125,8 @@ unrecoverable error from within the event loop.
% DHCP_DDNS_NO_MATCH No DNS servers match FQDN: %1
This is warning message issued when there are no domains in the configuration
-which match the cited FQDN. The DNS Update request for the FQDN cannot be
-processed.
+which match the cited fully qualified domain name (FQDN). The DNS Update
+request for the FQDN cannot be processed.
% DHCP_DDNS_PROCESS_INIT application init invoked
This is a debug message issued when the Dhcp-Ddns application enters
diff --git a/src/bin/d2/d_cfg_mgr.cc b/src/bin/d2/d_cfg_mgr.cc
index 365eab1..6a3175d 100644
--- a/src/bin/d2/d_cfg_mgr.cc
+++ b/src/bin/d2/d_cfg_mgr.cc
@@ -40,8 +40,6 @@ namespace d2 {
// *********************** DCfgContextBase *************************
-const bool DCfgContextBase::optional_ = true;
-
DCfgContextBase::DCfgContextBase():
boolean_values_(new BooleanStorage()),
uint32_values_(new Uint32Storage()),
@@ -143,30 +141,42 @@ DCfgMgrBase::parseConfig(isc::data::ConstElementPtr config_set) {
// elements are parsed in the order the value_map presents them.
if (parse_order_.size() > 0) {
- // NOTE: When using ordered parsing, the parse order list MUST
- // include every possible element id that the value_map may contain.
- // Entries in the map that are not in the parse order, would not be
- // parsed. For now we will flag this as a programmatic error. One
- // could attempt to adjust for this, by identifying such entries
- // and parsing them either first or last but which would be correct?
- // Better to make hold the engineer accountable.
- if (values_map.size() > parse_order_.size()) {
- LOG_ERROR(dctl_logger, DCTL_ORDER_ERROR);
- return (isc::config::createAnswer(1,
- "Configuration contains elements not in parse order"));
- }
-
// For each element_id in the parse order list, look for it in the
// value map. If the element exists in the map, pass it and it's
- // associated data in for parsing. If there is no matching entry
- // in the value map, then assume the element is optional and move
- // on to next element_id.
+ // associated data in for parsing.
+ // If there is no matching entry in the value map an error is
+ // thrown. Optional elements may not be used with ordered parsing.
+ int parsed_count = 0;
std::map<std::string, ConstElementPtr>::const_iterator it;
BOOST_FOREACH(element_id, parse_order_) {
it = values_map.find(element_id);
if (it != values_map.end()) {
+ ++parsed_count;
buildAndCommit(element_id, it->second);
}
+ else {
+ LOG_ERROR(dctl_logger, DCTL_ORDER_NO_ELEMENT)
+ .arg(element_id);
+ isc_throw(DCfgMgrBaseError, "Element:" << element_id <<
+ " is listed in the parse order but is not "
+ " present in the configuration");
+ }
+ }
+
+ // NOTE: When using ordered parsing, the parse order list MUST
+ // include every possible element id that the value_map may contain.
+ // Entries in the map that are not in the parse order, would not be
+ // parsed. For now we will flag this as a programmatic error. One
+ // could attempt to adjust for this, by identifying such entries
+ // and parsing them either first or last but which would be correct?
+ // Better to hold the engineer accountable. So, if we parsed none
+ // or we parsed fewer than are in the map; then either the parse i
+ // order is incomplete OR the map has unsupported values.
+ if (!parsed_count ||
+ (parsed_count && ((parsed_count + 1) < values_map.size()))) {
+ LOG_ERROR(dctl_logger, DCTL_ORDER_ERROR);
+ isc_throw(DCfgMgrBaseError,
+ "Configuration contains elements not in parse order");
}
} else {
// Order doesn't matter so iterate over the value map directly.
@@ -185,8 +195,7 @@ DCfgMgrBase::parseConfig(isc::data::ConstElementPtr config_set) {
} catch (const isc::Exception& ex) {
LOG_ERROR(dctl_logger, DCTL_PARSER_FAIL).arg(element_id).arg(ex.what());
answer = isc::config::createAnswer(1,
- string("Configuration parsing failed:") + ex.what() +
- " for element: " + element_id);
+ string("Configuration parsing failed: ") + ex.what());
// An error occurred, so make sure that we restore original context.
context_ = original_context;
@@ -202,7 +211,7 @@ void DCfgMgrBase::buildAndCommit(std::string& element_id,
// based on the element id.
ParserPtr parser = createConfigParser(element_id);
if (!parser) {
- isc_throw(DCfgMgrBaseError, std::string("Could not create parser"));
+ isc_throw(DCfgMgrBaseError, "Could not create parser");
}
try {
@@ -217,8 +226,8 @@ void DCfgMgrBase::buildAndCommit(std::string& element_id,
// nothing something we are concerned with here.)
parser->commit();
} catch (const isc::Exception& ex) {
- isc_throw(DCfgMgrBaseError, std::string("Could not build and commit")
- + ex.what());
+ isc_throw(DCfgMgrBaseError,
+ "Could not build and commit: " << ex.what());
} catch (...) {
isc_throw(DCfgMgrBaseError, "Non-ISC exception occurred");
}
diff --git a/src/bin/d2/d_cfg_mgr.h b/src/bin/d2/d_cfg_mgr.h
index 4f8b166..a527fdb 100644
--- a/src/bin/d2/d_cfg_mgr.h
+++ b/src/bin/d2/d_cfg_mgr.h
@@ -40,10 +40,9 @@ public:
/// Derivations simply add additional storage as needed. Note that this class
/// declares the pure virtual clone() method, its copy constructor is protected,
/// and its copy operator is inaccessible. Derivations must supply an
-/// implementation of clone that calls the base class copy constructor as
-/// well as performing whatever steps are necessary to copy its additional
-/// storage. This allows the management class to perform context backup and
-/// restoration without derivation specific knowledge using logic like
+/// implementation of clone that calls the base class copy constructor.
+/// This allows the management class to perform context backup and restoration
+/// without derivation specific knowledge using logic like
/// the following:
///
/// // Make a backup copy
@@ -55,7 +54,8 @@ public:
class DCfgContextBase {
public:
/// @brief Indicator that a configuration parameter is optional.
- static const bool optional_;
+ static const bool OPTIONAL = true;
+ static const bool REQUIRED = false;
/// @brief Constructor
DCfgContextBase();
@@ -129,13 +129,14 @@ public:
return (string_values_);
}
- /// @brief Creates a clone of this context object. As mentioned in the
- /// the class brief, derivation must supply an implementation that
- /// initializes the base class storage as well as its own. Typically
- /// the derivation's clone method would return the result of passing
- /// "*this" into its own copy constructor:
+ /// @brief Creates a clone of this context object.
///
- /// -----------------------------------------------------------------
+ /// As mentioned in the the class brief, derivation must supply an
+ /// implementation that initializes the base class storage as well as its
+ /// own. Typically the derivation's clone method would return the result
+ /// of passing "*this" into its own copy constructor:
+ ///
+ /// @code
/// class DStubContext : public DCfgContextBase {
/// public:
/// :
@@ -153,7 +154,7 @@ public:
/// // Here's the derivation's additional storage.
/// isc::dhcp::Uint32StoragePtr extra_values_;
/// :
- /// -----------------------------------------------------------------
+ /// @endcode
///
/// @return returns a raw pointer to the new clone.
virtual DCfgContextBase* clone() = 0;
@@ -189,17 +190,12 @@ typedef std::vector<std::string> ElementIdList;
/// configuration values, storing the parsed information in its converted form,
/// and retrieving the information on demand. It is intended to be the worker
/// class which is handed a set of configuration values to process by upper
-/// application management layers. Typically this call chain would look like
-/// this:
-/// External configuration event:
-/// --> Controller::configHandler(new configuration)
-/// --> Controller.updateConfig(new configuration)
-/// --> Controller.Process.configure(new configuration)
-/// --> Process.CfgMgr.parseConfig(new configuration)
+/// application management layers.
///
/// The class presents a public method for receiving new configurations,
/// parseConfig. This method coordinates the parsing effort as follows:
///
+/// @code
/// make backup copy of configuration context
/// for each top level element in new configuration
/// get derivation-specific parser for element
@@ -209,6 +205,7 @@ typedef std::vector<std::string> ElementIdList;
///
/// if an error occurred
/// restore configuration context from backup
+/// @endcode
///
/// After making a backup of the current context, it iterates over the top-level
/// elements in the new configuration. The order in which the elements are
@@ -219,16 +216,19 @@ typedef std::vector<std::string> ElementIdList;
///
/// This allows a derivation to specify the order in which its elements are
/// parsed if there are dependencies between elements.
+///
/// To parse a given element, its id is passed into createConfigParser,
/// which returns an instance of the appropriate parser. This method is
/// abstract so the derivation's implementation determines the type of parser
/// created. This isolates the knowledge of specific element ids and which
/// application specific parsers to derivation.
+///
/// Once the parser has been created, it is used to parse the data value
/// associated with the element id and update the context with the parsed
/// results.
-/// In the event that an error occurs, parsing is halted and the configuration
-/// context is restored from backup.
+///
+/// In the event that an error occurs, parsing is halted and the
+/// configuration context is restored from backup.
class DCfgMgrBase {
public:
/// @brief Constructor
@@ -254,12 +254,14 @@ public:
config_set);
/// @brief Adds a given element id to the end of the parse order list.
- /// The order in which elements are retrieved from this is FIFO. Elements
- /// should be added in the order in which they are to be parsed.
- //
+ ///
+ /// The order in which elements are retrieved from this is the order in
+ /// which they are added to the list. Derivations should use this method
+ /// to populate the parse order as part of their constructor.
+ ///
/// @param element_id is the string name of the element as it will appear
/// in the configuration set.
- void addToParseOrder(std::string& element_id){
+ void addToParseOrder(const std::string& element_id){
parse_order_.push_back(element_id);
}
@@ -278,9 +280,11 @@ public:
}
protected:
- /// @brief Given an element_id returns an instance of the appropriate
- /// parser. This method is abstract, isolating any direct knowledge of
- /// element_ids and parsers to within the application-specific derivation.
+ /// @brief Create a parser instance based on an element id.
+ ///
+ /// Given an element_id returns an instance of the appropriate parser.
+ /// This method is abstract, isolating any direct knowledge of element_ids
+ /// and parsers to within the application-specific derivation.
///
/// @param element_id is the string name of the element as it will appear
/// in the configuration set.
@@ -292,7 +296,9 @@ protected:
private:
- /// @brief Given an element_id and data value, instantiate the appropriate
+ /// @brief Parse a configuration element.
+ ///
+ /// Given an element_id and data value, instantiate the appropriate
/// parser, parse the data value, and commit the results.
///
/// @param element_id is the string name of the element as it will appear
@@ -304,9 +310,10 @@ private:
void buildAndCommit(std::string& element_id,
isc::data::ConstElementPtr value);
- /// @brief An FIFO list of element ids, used to dictate the element
- /// parsing order. If the list is empty, the natural order in the
- /// configuration set it used.
+ /// @brief A list of element ids which specifies the element parsing order.
+ ///
+ /// If the list is empty, the natural order in the configuration set
+ /// it used.
ElementIdList parse_order_;
/// @brief Pointer to the configuration context instance.
diff --git a/src/bin/d2/dhcp-ddns.spec b/src/bin/d2/dhcp-ddns.spec
index 1ea67f1..8e75e05 100644
--- a/src/bin/d2/dhcp-ddns.spec
+++ b/src/bin/d2/dhcp-ddns.spec
@@ -24,9 +24,40 @@
"item_optional": true,
"item_default": 51771
},
-
{
- "item_name": "foward_ddns",
+ "item_name": "tsig_keys",
+ "item_type": "list",
+ "item_optional": true,
+ "item_default": [],
+ "list_item_spec":
+ {
+ "item_name": "tsig_key",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {"algorithm" : "hmac_md5"},
+ "map_item_spec": [
+ {
+ "item_name": "name",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ },
+ {
+ "item_name": "algorithm",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ },
+ {
+ "item_name": "secret",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": ""
+ }]
+ }
+ },
+ {
+ "item_name": "forward_ddns",
"item_type": "map",
"item_optional": false,
"item_default": {},
@@ -171,3 +202,4 @@
]
}
}
+
diff --git a/src/bin/d2/tests/d2_cfg_mgr_unittests.cc b/src/bin/d2/tests/d2_cfg_mgr_unittests.cc
index 6727c12..4b212f1 100644
--- a/src/bin/d2/tests/d2_cfg_mgr_unittests.cc
+++ b/src/bin/d2/tests/d2_cfg_mgr_unittests.cc
@@ -105,6 +105,78 @@ bool checkServer(DnsServerInfoPtr server, const char* hostname,
return (result);
}
+/// @brief Convenience function which compares the contents of the given
+/// TSIGKeyInfo against the given set of values.
+///
+/// It is structured in such a way that each value is checked, and output
+/// is generate for all that do not match.
+///
+/// @param key is a pointer to the key to check against.
+/// @param name is the value to compare against key's name_.
+/// @param algorithm is the string value to compare against key's algorithm.
+/// @param secret is the value to compare against key's secret.
+///
+/// @return returns true if there is a match across the board, otherwise it
+/// returns false.
+bool checkKey(TSIGKeyInfoPtr key, const char* name,
+ const char *algorithm, const char* secret)
+{
+ // Return value, assume its a match.
+ bool result = true;
+ if (!key)
+ {
+ EXPECT_TRUE(key);
+ return false;
+ }
+
+ // Check name.
+ if (key->getName() != name) {
+ EXPECT_EQ(key->getName(),name);
+ result = false;
+ }
+
+ // Check algorithm.
+ if (key->getAlgorithm() != algorithm) {
+ EXPECT_EQ(key->getAlgorithm(), algorithm);
+ result = false;
+ }
+
+ // Check secret.
+ if (key->getSecret() != secret) {
+ EXPECT_EQ (key->getSecret(), secret);
+ result = false;
+ }
+
+ return (result);
+}
+
+/// @brief Test fixture class for testing DnsServerInfo parsing.
+class TSIGKeyInfoTest : public ConfigParseTest {
+public:
+
+ /// @brief Constructor
+ TSIGKeyInfoTest() {
+ reset();
+ }
+
+ /// @brief Destructor
+ ~TSIGKeyInfoTest() {
+ }
+
+ /// @brief Wipe out the current storage and parser and replace
+ /// them with new ones.
+ void reset() {
+ keys_.reset(new TSIGKeyInfoMap());
+ parser_.reset(new TSIGKeyInfoParser("test", keys_));
+ }
+
+ /// @brief Storage for "committing" keys.
+ TSIGKeyInfoMapPtr keys_;
+
+ /// @brief Pointer to the current parser instance.
+ isc::dhcp::ParserPtr parser_;
+};
+
/// @brief Test fixture class for testing DnsServerInfo parsing.
class DnsServerInfoTest : public ConfigParseTest {
public:
@@ -132,12 +204,254 @@ public:
isc::dhcp::ParserPtr parser_;
};
+
+/// @brief Test fixture class for testing DDnsDomain parsing.
+class DdnsDomainTest : public ConfigParseTest {
+public:
+
+ /// @brief Constructor
+ DdnsDomainTest() {
+ reset();
+ }
+
+ /// @brief Destructor
+ ~DdnsDomainTest() {
+ }
+
+ /// @brief Wipe out the current storage and parser and replace
+ /// them with new ones.
+ void reset() {
+ keys_.reset(new TSIGKeyInfoMap());
+ domains_.reset(new DdnsDomainMap());
+ parser_.reset(new DdnsDomainParser("test", domains_, keys_));
+ }
+
+ /// @brief Add TSIGKeyInfos to the key map
+ ///
+ /// @param name the name of the key
+ /// @param algorithm the algorithm of the key
+ /// @param secret the secret value of the key
+ void addKey(const std::string& name, const std::string& algorithm,
+ const std::string& secret) {
+ TSIGKeyInfoPtr key_info(new TSIGKeyInfo(name, algorithm, secret));
+ (*keys_)[name]=key_info;
+ }
+
+ /// @brief Storage for "committing" domains.
+ DdnsDomainMapPtr domains_;
+
+ /// @brief Storage for TSIGKeys
+ TSIGKeyInfoMapPtr keys_;
+
+ /// @brief Pointer to the current parser instance.
+ isc::dhcp::ParserPtr parser_;
+};
+
+/// @brief Tests the enforcement of data validation when parsing TSIGKeyInfos.
+/// It verifies that:
+/// 1. Name cannot be blank.
+/// 2. Algorithm cannot be blank.
+/// 3. Secret cannot be blank.
+/// @TODO TSIG keys are not fully functional. Only basic validation is
+/// currently supported. This test will need to expand as they evolve.
+TEST_F(TSIGKeyInfoTest, invalidEntryTests) {
+ // Config with a blank name entry.
+ std::string config = "{"
+ " \"name\": \"\" , "
+ " \"algorithm\": \"md5\" , "
+ " \"secret\": \"0123456789\" "
+ "}";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that build succeeds but commit fails on blank name.
+ EXPECT_NO_THROW(parser_->build(config_set_));
+ EXPECT_THROW(parser_->commit(), D2CfgError);
+
+ // Config with a blank algorithm entry.
+ config = "{"
+ " \"name\": \"d2_key_one\" , "
+ " \"algorithm\": \"\" , "
+ " \"secret\": \"0123456789\" "
+ "}";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that build succeeds but commit fails on blank algorithm.
+ EXPECT_NO_THROW(parser_->build(config_set_));
+ EXPECT_THROW(parser_->commit(), D2CfgError);
+
+ // Config with a blank secret entry.
+ config = "{"
+ " \"name\": \"d2_key_one\" , "
+ " \"algorithm\": \"md5\" , "
+ " \"secret\": \"\" "
+ "}";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that build succeeds but commit fails on blank secret.
+ EXPECT_NO_THROW(parser_->build(config_set_));
+ EXPECT_THROW(parser_->commit(), D2CfgError);
+}
+
+/// @brief Verifies that TSIGKeyInfo parsing creates a proper TSIGKeyInfo
+/// when given a valid combination of entries.
+TEST_F(TSIGKeyInfoTest, validEntryTests) {
+ // Valid entries for TSIG key, all items are required.
+ std::string config = "{"
+ " \"name\": \"d2_key_one\" , "
+ " \"algorithm\": \"md5\" , "
+ " \"secret\": \"0123456789\" "
+ "}";
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that it builds and commits without throwing.
+ ASSERT_NO_THROW(parser_->build(config_set_));
+ ASSERT_NO_THROW(parser_->commit());
+
+ // Verify the correct number of keys are present
+ int count = keys_->size();
+ EXPECT_EQ(count, 1);
+
+ // Find the key and retrieve it.
+ TSIGKeyInfoMap::iterator gotit = keys_->find("d2_key_one");
+ ASSERT_TRUE(gotit != keys_->end());
+ TSIGKeyInfoPtr& key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "d2_key_one", "md5", "0123456789"));
+}
+
+/// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
+/// entries is detected.
+TEST_F(TSIGKeyInfoTest, invalidTSIGKeyList) {
+ // Construct a list of keys with an invalid key entry.
+ std::string config = "["
+
+ " { \"name\": \"key1\" , "
+ " \"algorithm\": \"algo1\" ,"
+ " \"secret\": \"secret11\" "
+ " },"
+ " { \"name\": \"key2\" , "
+ " \"algorithm\": \"\" ,"
+ " \"secret\": \"secret12\" "
+ " },"
+ " { \"name\": \"key3\" , "
+ " \"algorithm\": \"algo3\" ,"
+ " \"secret\": \"secret13\" "
+ " }"
+ " ]";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Create the list parser.
+ isc::dhcp::ParserPtr parser;
+ ASSERT_NO_THROW(parser.reset(new TSIGKeyInfoListParser("test", keys_)));
+
+ // Verify that the list builds without errors.
+ ASSERT_NO_THROW(parser->build(config_set_));
+
+ // Verify that the list commit fails.
+ EXPECT_THROW(parser->commit(), D2CfgError);
+}
+
+/// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
+/// entries is detected.
+TEST_F(TSIGKeyInfoTest, duplicateTSIGKey) {
+ // Construct a list of keys with an invalid key entry.
+ std::string config = "["
+
+ " { \"name\": \"key1\" , "
+ " \"algorithm\": \"algo1\" ,"
+ " \"secret\": \"secret11\" "
+ " },"
+ " { \"name\": \"key2\" , "
+ " \"algorithm\": \"algo2\" ,"
+ " \"secret\": \"secret12\" "
+ " },"
+ " { \"name\": \"key1\" , "
+ " \"algorithm\": \"algo3\" ,"
+ " \"secret\": \"secret13\" "
+ " }"
+ " ]";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Create the list parser.
+ isc::dhcp::ParserPtr parser;
+ ASSERT_NO_THROW(parser.reset(new TSIGKeyInfoListParser("test", keys_)));
+
+ // Verify that the list builds without errors.
+ ASSERT_NO_THROW(parser->build(config_set_));
+
+ // Verify that the list commit fails.
+ EXPECT_THROW(parser->commit(), D2CfgError);
+}
+
+/// @brief Verifies a valid list of TSIG Keys parses correctly.
+TEST_F(TSIGKeyInfoTest, validTSIGKeyList) {
+ // Construct a valid list of keys.
+ std::string config = "["
+
+ " { \"name\": \"key1\" , "
+ " \"algorithm\": \"algo1\" ,"
+ " \"secret\": \"secret1\" "
+ " },"
+ " { \"name\": \"key2\" , "
+ " \"algorithm\": \"algo2\" ,"
+ " \"secret\": \"secret2\" "
+ " },"
+ " { \"name\": \"key3\" , "
+ " \"algorithm\": \"algo3\" ,"
+ " \"secret\": \"secret3\" "
+ " }"
+ " ]";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that the list builds and commits without errors.
+ // Create the list parser.
+ isc::dhcp::ParserPtr parser;
+ ASSERT_NO_THROW(parser.reset(new TSIGKeyInfoListParser("test", keys_)));
+ ASSERT_NO_THROW(parser->build(config_set_));
+ ASSERT_NO_THROW(parser->commit());
+
+ // Verify the correct number of keys are present
+ int count = keys_->size();
+ ASSERT_EQ(count, 3);
+
+ // Find the 1st key and retrieve it.
+ TSIGKeyInfoMap::iterator gotit = keys_->find("key1");
+ ASSERT_TRUE(gotit != keys_->end());
+ TSIGKeyInfoPtr& key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "key1", "algo1", "secret1"));
+
+ // Find the 2nd key and retrieve it.
+ gotit = keys_->find("key2");
+ ASSERT_TRUE(gotit != keys_->end());
+ key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "key2", "algo2", "secret2"));
+
+ // Find the 3rd key and retrieve it.
+ gotit = keys_->find("key3");
+ ASSERT_TRUE(gotit != keys_->end());
+ key = gotit->second;
+
+ // Verify the key contents.
+ EXPECT_TRUE(checkKey(key, "key3", "algo3", "secret3"));
+}
+
/// @brief Tests the enforcement of data validation when parsing DnsServerInfos.
/// It verifies that:
/// 1. Specifying both a hostname and an ip address is not allowed.
/// 2. Specifying both blank a hostname and blank ip address is not allowed.
/// 3. Specifying a negative port number is not allowed.
-TEST_F(DnsServerInfoTest, invalidEntyTests) {
+TEST_F(DnsServerInfoTest, invalidEntryTests) {
// Create a config in which both host and ip address are supplied.
// Verify that it builds without throwing but commit fails.
std::string config = "{ \"hostname\": \"pegasus.tmark\", "
@@ -162,13 +476,14 @@ TEST_F(DnsServerInfoTest, invalidEntyTests) {
EXPECT_THROW (parser_->build(config_set_), isc::BadValue);
}
+
/// @brief Verifies that DnsServerInfo parsing creates a proper DnsServerInfo
/// when given a valid combination of entries.
/// It verifies that:
/// 1. A DnsServerInfo entry is correctly made, when given only a hostname.
/// 2. A DnsServerInfo entry is correctly made, when given ip address and port.
/// 3. A DnsServerInfo entry is correctly made, when given only an ip address.
-TEST_F(DnsServerInfoTest, validEntyTests) {
+TEST_F(DnsServerInfoTest, validEntryTests) {
// Valid entries for dynamic host
std::string config = "{ \"hostname\": \"pegasus.tmark\" }";
ASSERT_NO_THROW(fromJSON(config));
@@ -184,8 +499,8 @@ TEST_F(DnsServerInfoTest, validEntyTests) {
// Verify the server exists and has the correct values.
DnsServerInfoPtr server = (*servers_)[0];
EXPECT_TRUE(checkServer(server, "pegasus.tmark",
- DnsServerInfo::empty_ip_str,
- DnsServerInfo::standard_dns_port));
+ DnsServerInfo::EMPTY_IP_STR,
+ DnsServerInfo::STANDARD_DNS_PORT));
// Start over for a new test.
reset();
@@ -225,7 +540,7 @@ TEST_F(DnsServerInfoTest, validEntyTests) {
// Verify the server exists and has the correct values.
server = (*servers_)[0];
EXPECT_TRUE(checkServer(server, "", "192.168.2.5",
- DnsServerInfo::standard_dns_port));
+ DnsServerInfo::STANDARD_DNS_PORT));
}
/// @brief Verifies that attempting to parse an invalid list of DnsServerInfo
@@ -273,18 +588,18 @@ TEST_F(ConfigParseTest, validServerList) {
// Verify the first server exists and has the correct values.
DnsServerInfoPtr server = (*servers)[0];
- EXPECT_TRUE(checkServer(server, "one.tmark", DnsServerInfo::empty_ip_str,
- DnsServerInfo::standard_dns_port));
+ EXPECT_TRUE(checkServer(server, "one.tmark", DnsServerInfo::EMPTY_IP_STR,
+ DnsServerInfo::STANDARD_DNS_PORT));
// Verify the second server exists and has the correct values.
server = (*servers)[1];
- EXPECT_TRUE(checkServer(server, "two.tmark", DnsServerInfo::empty_ip_str,
- DnsServerInfo::standard_dns_port));
+ EXPECT_TRUE(checkServer(server, "two.tmark", DnsServerInfo::EMPTY_IP_STR,
+ DnsServerInfo::STANDARD_DNS_PORT));
// Verify the third server exists and has the correct values.
server = (*servers)[2];
- EXPECT_TRUE(checkServer(server, "three.tmark", DnsServerInfo::empty_ip_str,
- DnsServerInfo::standard_dns_port));
+ EXPECT_TRUE(checkServer(server, "three.tmark", DnsServerInfo::EMPTY_IP_STR,
+ DnsServerInfo::STANDARD_DNS_PORT));
}
/// @brief Tests the enforcement of data validation when parsing DdnsDomains.
@@ -293,16 +608,12 @@ TEST_F(ConfigParseTest, validServerList) {
/// 2. The name entry is not optional.
/// 3. The server list man not be empty.
/// 4. That a mal-formed server entry is detected.
-TEST_F(ConfigParseTest, invalidDdnsDomainEntry) {
+/// 5. That an undefined key name is detected.
+TEST_F(DdnsDomainTest, invalidDdnsDomainEntry) {
// Verify that attempting to construct the parser with null storage fails.
- DdnsDomainStoragePtr domains;
- ASSERT_THROW(new DdnsDomainParser("test", domains), D2CfgError);
-
- // Create domain storage for the parser, and then instantiate the
- // parser.
- domains.reset(new DdnsDomainStorage());
- DdnsDomainParser *parser = NULL;
- ASSERT_NO_THROW(parser = new DdnsDomainParser("test", domains));
+ DdnsDomainMapPtr domains;
+ ASSERT_THROW(isc::dhcp::ParserPtr(
+ new DdnsDomainParser("test", domains, keys_)), D2CfgError);
// Create a domain configuration without a name
std::string config = "{ \"key_name\": \"d2_key.tmark.org\" , "
@@ -316,8 +627,8 @@ TEST_F(ConfigParseTest, invalidDdnsDomainEntry) {
ASSERT_NO_THROW(fromJSON(config));
// Verify that the domain configuration builds but commit fails.
- ASSERT_NO_THROW(parser->build(config_set_));
- ASSERT_THROW(parser->commit(), isc::dhcp::DhcpConfigError);
+ ASSERT_NO_THROW(parser_->build(config_set_));
+ ASSERT_THROW(parser_->commit(), isc::dhcp::DhcpConfigError);
// Create a domain configuration with an empty server list.
config = "{ \"name\": \"tmark.org\" , "
@@ -327,7 +638,7 @@ TEST_F(ConfigParseTest, invalidDdnsDomainEntry) {
ASSERT_NO_THROW(fromJSON(config));
// Verify that the domain configuration build fails.
- ASSERT_THROW(parser->build(config_set_), D2CfgError);
+ ASSERT_THROW(parser_->build(config_set_), D2CfgError);
// Create a domain configuration with a mal-formed server entry.
config = "{ \"name\": \"tmark.org\" , "
@@ -338,17 +649,28 @@ TEST_F(ConfigParseTest, invalidDdnsDomainEntry) {
ASSERT_NO_THROW(fromJSON(config));
// Verify that the domain configuration build fails.
- ASSERT_THROW(parser->build(config_set_), isc::BadValue);
-}
+ ASSERT_THROW(parser_->build(config_set_), isc::BadValue);
+ // Create a domain configuration without an defined key name
+ config = "{ \"name\": \"tmark.org\" , "
+ " \"key_name\": \"d2_key.tmark.org\" , "
+ " \"dns_servers\" : [ "
+ " { \"ip_address\": \"127.0.0.3\" , "
+ " \"port\": 300 } ] } ";
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that the domain configuration build succeeds but commit fails.
+ ASSERT_NO_THROW(parser_->build(config_set_));
+ ASSERT_THROW(parser_->commit(), D2CfgError);
+}
/// @brief Verifies the basics of parsing DdnsDomains.
/// It verifies that:
/// 1. Valid construction of DdnsDomainParser functions.
/// 2. Given a valid, configuration entry, DdnsDomainParser parses
/// correctly.
-/// (It indirectly verifies the operation of DdnsDomainStorage).
-TEST_F(ConfigParseTest, ddnsDomainParsing) {
+/// (It indirectly verifies the operation of DdnsDomainMap).
+TEST_F(DdnsDomainTest, ddnsDomainParsing) {
// Create a valid domain configuration entry containing three valid
// servers.
std::string config =
@@ -363,24 +685,21 @@ TEST_F(ConfigParseTest, ddnsDomainParsing) {
" \"port\": 300 } ] } ";
ASSERT_NO_THROW(fromJSON(config));
- // Create domain storage for the parser, and then instantiate the
- // parser. This verifies that valid parser construction.
- DdnsDomainStoragePtr domains(new DdnsDomainStorage());
- DdnsDomainParser *parser = NULL;
- ASSERT_NO_THROW(parser = new DdnsDomainParser("test", domains));
+ // Add a TSIG key to the test key map, so key validation will pass.
+ addKey("d2_key.tmark.org", "md5", "0123456789");
// Verify that the domain configuration builds and commits without error.
- ASSERT_NO_THROW(parser->build(config_set_));
- ASSERT_NO_THROW(parser->commit());
+ ASSERT_NO_THROW(parser_->build(config_set_));
+ ASSERT_NO_THROW(parser_->commit());
// Verify that the domain storage contains the correct number of domains.
- int count = domains->size();
+ int count = domains_->size();
EXPECT_EQ(count, 1);
// Verify that the expected domain exists and can be retrieved from
// the storage.
- DdnsDomainStorage::iterator gotit = domains->find("tmark.org");
- ASSERT_TRUE(gotit != domains->end());
+ DdnsDomainMap::iterator gotit = domains_->find("tmark.org");
+ ASSERT_TRUE(gotit != domains_->end());
DdnsDomainPtr& domain = gotit->second;
// Verify the name and key_name values.
@@ -414,7 +733,7 @@ TEST_F(ConfigParseTest, ddnsDomainParsing) {
/// @brief Tests the fundamentals of parsing DdnsDomain lists.
/// This test verifies that given a valid domain list configuration
/// it will accurately parse and populate each domain in the list.
-TEST_F(ConfigParseTest, DdnsDomainListParsing) {
+TEST_F(DdnsDomainTest, DdnsDomainListParsing) {
// Create a valid domain list configuration, with two domains
// that have three servers each.
std::string config =
@@ -442,23 +761,26 @@ TEST_F(ConfigParseTest, DdnsDomainListParsing) {
ASSERT_NO_THROW(fromJSON(config));
- // Create domain storage for the parser, and then instantiate the
- // parser.
- DdnsDomainStoragePtr domains(new DdnsDomainStorage());
- DdnsDomainListParser *parser = NULL;
- ASSERT_NO_THROW(parser = new DdnsDomainListParser("test", domains));
+ // Add keys to key map so key validation passes.
+ addKey("d2_key.tmark.org", "algo1", "secret1");
+ addKey("d2_key.billcat.net", "algo2", "secret2");
+
+ // Create the list parser
+ isc::dhcp::ParserPtr list_parser;
+ ASSERT_NO_THROW(list_parser.reset(
+ new DdnsDomainListParser("test", domains_, keys_)));
// Verify that the domain configuration builds and commits without error.
- ASSERT_NO_THROW(parser->build(config_set_));
- ASSERT_NO_THROW(parser->commit());
+ ASSERT_NO_THROW(list_parser->build(config_set_));
+ ASSERT_NO_THROW(list_parser->commit());
// Verify that the domain storage contains the correct number of domains.
- int count = domains->size();
+ int count = domains_->size();
EXPECT_EQ(count, 2);
// Verify that the first domain exists and can be retrieved.
- DdnsDomainStorage::iterator gotit = domains->find("tmark.org");
- ASSERT_TRUE(gotit != domains->end());
+ DdnsDomainMap::iterator gotit = domains_->find("tmark.org");
+ ASSERT_TRUE(gotit != domains_->end());
DdnsDomainPtr& domain = gotit->second;
// Verify the name and key_name values of the first domain.
@@ -484,8 +806,8 @@ TEST_F(ConfigParseTest, DdnsDomainListParsing) {
EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
// Verify second domain
- gotit = domains->find("billcat.net");
- ASSERT_TRUE(gotit != domains->end());
+ gotit = domains_->find("billcat.net");
+ ASSERT_TRUE(gotit != domains_->end());
domain = gotit->second;
// Verify the name and key_name values of the second domain.
@@ -512,7 +834,7 @@ TEST_F(ConfigParseTest, DdnsDomainListParsing) {
}
/// @brief Tests that a domain list configuration cannot contain duplicates.
-TEST_F(ConfigParseTest, duplicateDomainTest) {
+TEST_F(DdnsDomainTest, duplicateDomainTest) {
// Create a domain list configuration that contains two domains with
// the same name.
std::string config =
@@ -527,17 +849,16 @@ TEST_F(ConfigParseTest, duplicateDomainTest) {
" { \"ip_address\": \"127.0.0.3\" , "
" \"port\": 300 } ] } "
"] ";
-
ASSERT_NO_THROW(fromJSON(config));
- // Create the domain storage pointer and the parser.
- DdnsDomainStoragePtr domains(new DdnsDomainStorage());
- DdnsDomainListParser *parser = NULL;
- ASSERT_NO_THROW(parser = new DdnsDomainListParser("test", domains));
+ // Create the list parser
+ isc::dhcp::ParserPtr list_parser;
+ ASSERT_NO_THROW(list_parser.reset(
+ new DdnsDomainListParser("test", domains_, keys_)));
// Verify that the parse build succeeds but the commit fails.
- ASSERT_NO_THROW(parser->build(config_set_));
- ASSERT_THROW(parser->commit(), D2CfgError);
+ ASSERT_NO_THROW(list_parser->build(config_set_));
+ ASSERT_THROW(list_parser->commit(), D2CfgError);
}
/// @brief Tests construction of D2CfgMgr
@@ -575,6 +896,18 @@ TEST_F(D2CfgMgrTest, fullConfigTest) {
"\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ "\"tsig_keys\": ["
+ "{"
+ " \"name\": \"d2_key.tmark.org\" , "
+ " \"algorithm\": \"md5\" , "
+ " \"secret\": \"ssh-dont-tell\" "
+ "},"
+ "{"
+ " \"name\": \"d2_key.billcat.net\" , "
+ " \"algorithm\": \"md5\" , "
+ " \"secret\": \"ollie-ollie-in-free\" "
+ "}"
+ "],"
"\"forward_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \"tmark.org\" , "
@@ -615,7 +948,7 @@ TEST_F(D2CfgMgrTest, fullConfigTest) {
// Verify that we can parse the configuration.
answer_ = cfg_mgr_->parseConfig(config_set_);
- EXPECT_TRUE(checkAnswer(0));
+ ASSERT_TRUE(checkAnswer(0));
// Verify that the D2 context can be retrieved and is not null.
D2CfgContextPtr context;
@@ -639,7 +972,7 @@ TEST_F(D2CfgMgrTest, fullConfigTest) {
ASSERT_TRUE(mgr);
// Verify that the forward manager has the correct number of domains.
- DdnsDomainStoragePtr domains = mgr->getDomains();
+ DdnsDomainMapPtr domains = mgr->getDomains();
ASSERT_TRUE(domains);
int count = domains->size();
EXPECT_EQ(count, 2);
@@ -648,7 +981,7 @@ TEST_F(D2CfgMgrTest, fullConfigTest) {
// NOTE that since prior tests have validated server parsing, we are are
// assuming that the servers did in fact parse correctly if the correct
// number of them are there.
- DdnsDomainPtrPair domain_pair;
+ DdnsDomainMapPair domain_pair;
BOOST_FOREACH(domain_pair, (*domains)) {
DdnsDomainPtr domain = domain_pair.second;
DnsServerInfoStoragePtr servers = domain->getServers();
@@ -695,6 +1028,7 @@ TEST_F(D2CfgMgrTest, forwardMatchTest) {
"\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ "\"tsig_keys\": [] ,"
"\"forward_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \"tmark.org\" , "
@@ -711,7 +1045,10 @@ TEST_F(D2CfgMgrTest, forwardMatchTest) {
" \"dns_servers\" : [ "
" { \"hostname\": \"global.net\" } "
" ] } "
- "] } }";
+ "] }, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
ASSERT_NO_THROW(fromJSON(config));
// Verify that we can parse the configuration.
@@ -757,6 +1094,7 @@ TEST_F(D2CfgMgrTest, matchNoWildcard) {
"\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ "\"tsig_keys\": [] ,"
"\"forward_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \"tmark.org\" , "
@@ -768,7 +1106,9 @@ TEST_F(D2CfgMgrTest, matchNoWildcard) {
" \"dns_servers\" : [ "
" { \"ip_address\": \"127.0.0.2\" } "
" ] } "
- "] } }";
+ "] }, "
+ "\"reverse_ddns\" : {} "
+ " }";
ASSERT_NO_THROW(fromJSON(config));
@@ -802,13 +1142,16 @@ TEST_F(D2CfgMgrTest, matchAll) {
"\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ "\"tsig_keys\": [] ,"
"\"forward_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \"*\" , "
" \"dns_servers\" : [ "
" { \"ip_address\": \"127.0.0.1\" } "
" ] } "
- "] } }";
+ "] }, "
+ "\"reverse_ddns\" : {} "
+ "}";
ASSERT_NO_THROW(fromJSON(config));
@@ -846,6 +1189,8 @@ TEST_F(D2CfgMgrTest, matchReverse) {
"\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ "\"tsig_keys\": [] ,"
+ "\"forward_ddns\" : {}, "
"\"reverse_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \"100.168.192.in-addr.arpa\" , "
@@ -893,5 +1238,45 @@ TEST_F(D2CfgMgrTest, matchReverse) {
ASSERT_THROW(cfg_mgr_->matchReverse("", match), D2CfgError);
}
+TEST_F(D2CfgMgrTest, tsigTest) {
+ std::string config = "{ "
+ "\"interface\" : \"eth1\" , "
+ "\"ip_address\" : \"192.168.1.33\" , "
+ "\"port\" : 88 , "
+ "\"tsig_keys\": [] ,"
+ "\"forward_ddns\" : {"
+ "\"ddns_domains\": [ "
+ "{ \"name\": \"tmark.org\" , "
+ " \"dns_servers\" : [ "
+ " { \"ip_address\": \"127.0.0.1\" } "
+ " ] } "
+ ", "
+ "{ \"name\": \"one.tmark.org\" , "
+ " \"dns_servers\" : [ "
+ " { \"ip_address\": \"127.0.0.2\" } "
+ " ] } "
+ "] },"
+ "\"reverse_ddns\" : {"
+ "\"ddns_domains\": [ "
+ "{ \"name\": \"100.168.192.in-addr.arpa\" , "
+ " \"dns_servers\" : [ "
+ " { \"ip_address\": \"127.0.0.1\" } "
+ " ] }, "
+ "{ \"name\": \"168.192.in-addr.arpa\" , "
+ " \"dns_servers\" : [ "
+ " { \"ip_address\": \"127.0.0.1\" } "
+ " ] }, "
+ "{ \"name\": \"*\" , "
+ " \"dns_servers\" : [ "
+ " { \"ip_address\": \"127.0.0.1\" } "
+ " ] } "
+ "] } }";
+
+ ASSERT_NO_THROW(fromJSON(config));
+
+ // Verify that we can parse the configuration.
+ answer_ = cfg_mgr_->parseConfig(config_set_);
+ ASSERT_TRUE(checkAnswer(0));
+}
} // end of anonymous namespace
diff --git a/src/bin/d2/tests/d_cfg_mgr_unittests.cc b/src/bin/d2/tests/d_cfg_mgr_unittests.cc
index 779f3ba..bfe9920 100644
--- a/src/bin/d2/tests/d_cfg_mgr_unittests.cc
+++ b/src/bin/d2/tests/d_cfg_mgr_unittests.cc
@@ -88,17 +88,17 @@ public:
/// 3. Destruction works properly.
/// 4. Construction with a null context is not allowed.
TEST(DCfgMgrBase, construction) {
- DCfgMgrBase *cfg_mgr = NULL;
+ DCfgMgrBasePtr cfg_mgr;
// Verify that configuration manager constructions without error.
- ASSERT_NO_THROW(cfg_mgr=new DStubCfgMgr());
+ ASSERT_NO_THROW(cfg_mgr.reset(new DStubCfgMgr()));
// Verify that the context can be retrieved and is not null.
DCfgContextBasePtr context = cfg_mgr->getContext();
EXPECT_TRUE(context);
// Verify that the manager can be destructed without error.
- EXPECT_NO_THROW(delete cfg_mgr);
+ EXPECT_NO_THROW(cfg_mgr.reset());
// Verify that an attempt to construct a manger with a null context fails.
ASSERT_THROW(DCtorTestCfgMgr(), DCfgMgrBaseError);
@@ -145,6 +145,7 @@ TEST_F(DStubCfgMgrTest, basicParseTest) {
/// 2. A parse order list with too few elements is detected.
/// 3. Ordered parsing parses the elements in the order specified by the
/// configuration manager's parse order list.
+/// 4. A parse order list with too many elements is detected.
TEST_F(DStubCfgMgrTest, parseOrderTest) {
// Element ids used for test.
std::string charlie("charlie");
@@ -213,6 +214,17 @@ TEST_F(DStubCfgMgrTest, parseOrderTest) {
// Verify that the parsed order is the order we configured.
EXPECT_TRUE(cfg_mgr_->getParseOrder() == cfg_mgr_->parsed_order_);
+
+ // Create a parse order list that has too many entries. Verify that
+ // when parsing the test config, it fails.
+ cfg_mgr_->addToParseOrder("delta");
+
+ // Verify the parse order list is the size we expect.
+ EXPECT_EQ(4, cfg_mgr_->getParseOrder().size());
+
+ // Verify the configuration fails.
+ answer_ = cfg_mgr_->parseConfig(config_set_);
+ EXPECT_TRUE(checkAnswer(1));
}
/// @brief Tests that element ids supported by the base class as well as those
diff --git a/src/bin/d2/tests/d_test_stubs.cc b/src/bin/d2/tests/d_test_stubs.cc
index d07419f..5d9077d 100644
--- a/src/bin/d2/tests/d_test_stubs.cc
+++ b/src/bin/d2/tests/d_test_stubs.cc
@@ -25,13 +25,18 @@ const char* valid_d2_config = "{ "
"\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ "\"tsig_keys\": ["
+ "{ \"name\": \"d2_key.tmark.org\" , "
+ " \"algorithm\": \"md5\" ,"
+ " \"secret\": \"0123456989\" "
+ "} ],"
"\"forward_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \"tmark.org\" , "
" \"key_name\": \"d2_key.tmark.org\" , "
" \"dns_servers\" : [ "
" { \"hostname\": \"one.tmark\" } "
- " ] } ] }, "
+ "] } ] }, "
"\"reverse_ddns\" : {"
"\"ddns_domains\": [ "
"{ \"name\": \" 0.168.192.in.addr.arpa.\" , "
@@ -296,7 +301,7 @@ DStubCfgMgr::createConfigParser(const std::string& element_id) {
// to test parse ordering, by permitting a wide range of element ids
// to "succeed" without specifically supporting them.
if (SimFailure::shouldFailOn(SimFailure::ftElementUnknown)) {
- isc_throw(DCfgMgrBaseError, "Configuration parameter not supported"
+ isc_throw(DCfgMgrBaseError, "Configuration parameter not supported: "
<< element_id);
}
diff --git a/src/bin/d2/tests/d_test_stubs.h b/src/bin/d2/tests/d_test_stubs.h
index 73361b5..ec23efe 100644
--- a/src/bin/d2/tests/d_test_stubs.h
+++ b/src/bin/d2/tests/d_test_stubs.h
@@ -628,10 +628,12 @@ public:
isc::data::ConstElementPtr comment;
comment = isc::config::parseAnswer(rcode, answer_);
// Handy for diagnostics
- // if (rcode != 0) {
- // std::cout << "checkAnswer rcode:" << rcode << " comment: "
- // << *comment << std::endl;
- //}
+ #if 1
+ if (rcode != 0) {
+ std::cout << "checkAnswer rcode:" << rcode << " comment: "
+ << *comment << std::endl;
+ }
+ #endif
return (rcode == should_be);
}
More information about the bind10-changes
mailing list