// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. #include #include #include #include #include #include #include #include #include #include namespace isc { namespace d2 { // *********************** D2Params ************************* const char *D2Params::DFT_IP_ADDRESS = "127.0.0.1"; const size_t D2Params::DFT_PORT = 53001; const size_t D2Params::DFT_DNS_SERVER_TIMEOUT = 100; const char *D2Params::DFT_NCR_PROTOCOL = "UDP"; const char *D2Params::DFT_NCR_FORMAT = "JSON"; D2Params::D2Params(const isc::asiolink::IOAddress& ip_address, const size_t port, const size_t dns_server_timeout, const dhcp_ddns::NameChangeProtocol& ncr_protocol, const dhcp_ddns::NameChangeFormat& ncr_format) : ip_address_(ip_address), port_(port), dns_server_timeout_(dns_server_timeout), ncr_protocol_(ncr_protocol), ncr_format_(ncr_format) { validateContents(); } D2Params::D2Params() : ip_address_(isc::asiolink::IOAddress(DFT_IP_ADDRESS)), port_(DFT_PORT), dns_server_timeout_(DFT_DNS_SERVER_TIMEOUT), ncr_protocol_(dhcp_ddns::NCR_UDP), ncr_format_(dhcp_ddns::FMT_JSON) { validateContents(); } D2Params::~D2Params(){}; void D2Params::validateContents() { if ((ip_address_.toText() == "0.0.0.0") || (ip_address_.toText() == "::")) { isc_throw(D2CfgError, "D2Params: IP address cannot be \"" << ip_address_ << "\""); } if (port_ == 0) { isc_throw(D2CfgError, "D2Params: port cannot be 0"); } if (dns_server_timeout_ < 1) { isc_throw(D2CfgError, "D2Params: DNS server timeout must be larger than 0"); } if (ncr_format_ != dhcp_ddns::FMT_JSON) { isc_throw(D2CfgError, "D2Params: NCR Format:" << dhcp_ddns::ncrFormatToString(ncr_format_) << " is not yet supported"); } if (ncr_protocol_ != dhcp_ddns::NCR_UDP) { isc_throw(D2CfgError, "D2Params: NCR Protocol:" << dhcp_ddns::ncrProtocolToString(ncr_protocol_) << " is not yet supported"); } } std::string D2Params::getConfigSummary() const { std::ostringstream s; s << "listening on " << getIpAddress() << ", port " << getPort() << ", using " << ncrProtocolToString(ncr_protocol_); return (s.str()); } bool D2Params::operator == (const D2Params& other) const { return ((ip_address_ == other.ip_address_) && (port_ == other.port_) && (dns_server_timeout_ == other.dns_server_timeout_) && (ncr_protocol_ == other.ncr_protocol_) && (ncr_format_ == other.ncr_format_)); } bool D2Params::operator != (const D2Params& other) const { return (!(*this == other)); } std::string D2Params::toText() const { std::ostringstream stream; stream << ", ip_address: " << ip_address_.toText() << ", port: " << port_ << ", dns_server_timeout_: " << dns_server_timeout_ << ", ncr_protocol: " << dhcp_ddns::ncrProtocolToString(ncr_protocol_) << ", ncr_format: " << ncr_format_ << dhcp_ddns::ncrFormatToString(ncr_format_); return (stream.str()); } std::ostream& operator<<(std::ostream& os, const D2Params& config) { os << config.toText(); return (os); } // *********************** TSIGKeyInfo ************************* // Note these values match correpsonding values for Bind9's // dnssec-keygen const char* TSIGKeyInfo::HMAC_MD5_STR = "HMAC-MD5"; const char* TSIGKeyInfo::HMAC_SHA1_STR = "HMAC-SHA1"; const char* TSIGKeyInfo::HMAC_SHA224_STR = "HMAC-SHA224"; const char* TSIGKeyInfo::HMAC_SHA256_STR = "HMAC-SHA256"; const char* TSIGKeyInfo::HMAC_SHA384_STR = "HMAC-SHA384"; const char* TSIGKeyInfo::HMAC_SHA512_STR = "HMAC-SHA512"; TSIGKeyInfo::TSIGKeyInfo(const std::string& name, const std::string& algorithm, const std::string& secret) :name_(name), algorithm_(algorithm), secret_(secret), tsig_key_() { remakeKey(); } TSIGKeyInfo::~TSIGKeyInfo() { } const dns::Name& TSIGKeyInfo::stringToAlgorithmName(const std::string& algorithm_id) { if (boost::iequals(algorithm_id, HMAC_MD5_STR)) { return (dns::TSIGKey::HMACMD5_NAME()); } else if (boost::iequals(algorithm_id, HMAC_SHA1_STR)) { return (dns::TSIGKey::HMACSHA1_NAME()); } else if (boost::iequals(algorithm_id, HMAC_SHA224_STR)) { return (dns::TSIGKey::HMACSHA224_NAME()); } else if (boost::iequals(algorithm_id, HMAC_SHA256_STR)) { return (dns::TSIGKey::HMACSHA256_NAME()); } else if (boost::iequals(algorithm_id, HMAC_SHA384_STR)) { return (dns::TSIGKey::HMACSHA384_NAME()); } else if (boost::iequals(algorithm_id, HMAC_SHA512_STR)) { return (dns::TSIGKey::HMACSHA512_NAME()); } isc_throw(BadValue, "Unknown TSIG Key algorithm: " << algorithm_id); } void TSIGKeyInfo::remakeKey() { try { // Since our secret value is base64 encoded already, we need to // build the input string for the appropriate TSIGKey constructor. // If secret isn't a valid base64 value, the constructor will throw. std::ostringstream stream; stream << dns::Name(name_).toText() << ":" << secret_ << ":" << stringToAlgorithmName(algorithm_); tsig_key_.reset(new dns::TSIGKey(stream.str())); } catch (const std::exception& ex) { isc_throw(D2CfgError, "Cannot make TSIGKey: " << ex.what()); } } // *********************** DnsServerInfo ************************* 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), enabled_(enabled) { } DnsServerInfo::~DnsServerInfo() { } std::string DnsServerInfo::toText() const { std::ostringstream stream; stream << (getIpAddress().toText()) << " port:" << getPort(); return (stream.str()); } std::ostream& operator<<(std::ostream& os, const DnsServerInfo& server) { os << server.toText(); return (os); } // *********************** DdnsDomain ************************* DdnsDomain::DdnsDomain(const std::string& name, DnsServerInfoStoragePtr servers, const TSIGKeyInfoPtr& tsig_key_info) : name_(name), servers_(servers), tsig_key_info_(tsig_key_info) { } DdnsDomain::~DdnsDomain() { } const std::string DdnsDomain::getKeyName() const { if (tsig_key_info_) { return (tsig_key_info_->getName()); } return (""); } // *********************** DdnsDomainLstMgr ************************* const char* DdnsDomainListMgr::wildcard_domain_name_ = "*"; DdnsDomainListMgr::DdnsDomainListMgr(const std::string& name) : name_(name), domains_(new DdnsDomainMap()) { } DdnsDomainListMgr::~DdnsDomainListMgr () { } void DdnsDomainListMgr::setDomains(DdnsDomainMapPtr domains) { if (!domains) { isc_throw(D2CfgError, "DdnsDomainListMgr::setDomains: Domain list may not be null"); } domains_ = domains; // 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; } } bool DdnsDomainListMgr::matchDomain(const std::string& fqdn, DdnsDomainPtr& domain) { // First check the case of one domain to rule them all. if ((size() == 1) && (wildcard_domain_)) { domain = wildcard_domain_; return (true); } // Iterate over the domain map looking for the domain which matches // the longest portion of the given fqdn. size_t req_len = fqdn.size(); size_t match_len = 0; DdnsDomainMapPair map_pair; DdnsDomainPtr best_match; BOOST_FOREACH (map_pair, *domains_) { std::string domain_name = map_pair.first; size_t dom_len = domain_name.size(); // If the domain name is longer than the fqdn, then it cant be match. if (req_len < dom_len) { continue; } // If the lengths are identical and the names match we're done. if (req_len == dom_len) { if (boost::iequals(fqdn, domain_name)) { // exact match, done domain = map_pair.second; return (true); } } else { // The fqdn is longer than the domain name. Adjust the start // point of comparison by the excess in length. Only do the // comparison if the adjustment lands on a boundary. This // prevents "onetwo.net" from matching "two.net". size_t offset = req_len - dom_len; if ((fqdn[offset - 1] == '.') && (boost::iequals(fqdn.substr(offset), domain_name))) { // Fqdn contains domain name, keep it if its better than // any we have matched so far. if (dom_len > match_len) { match_len = dom_len; best_match = map_pair.second; } } } } if (!best_match) { // 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); } LOG_WARN(dctl_logger, DHCP_DDNS_NO_MATCH).arg(fqdn); return (false); } domain = best_match; return (true); } // *************************** 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, config_pair.second-> getPosition())); parser->build(config_pair.second); parser->commit(); } std::string name; std::string algorithm; std::string secret; std::map pos; // Fetch the key's parsed scalar values from parser's local storage. // All are required, if any are missing we'll throw. try { pos["name"] = local_scalars_.getParam("name", name); pos["algorithm"] = local_scalars_.getParam("algorithm", algorithm); pos["secret"] = local_scalars_.getParam("secret", secret); } catch (const std::exception& ex) { isc_throw(D2CfgError, "TSIG Key incomplete : " << ex.what() << " (" << key_config->getPosition() << ")"); } // Name cannot be blank. if (name.empty()) { isc_throw(D2CfgError, "TSIG key must specify name (" << pos["name"] << ")"); } // 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 name specified : " << name << " (" << pos["name"] << ")"); } // Algorithm must be valid. try { TSIGKeyInfo::stringToAlgorithmName(algorithm); } catch (const std::exception& ex) { isc_throw(D2CfgError, "TSIG key : " << ex.what() << " (" << pos["algorithm"] << ")"); } // Secret cannot be blank. // Cryptolink lib doesn't offer any way to validate these. As long as it // isn't blank we'll accept it. If the content is bad, the call to in // TSIGKeyInfo::remakeKey() made in the TSIGKeyInfo ctor will throw. // We'll deal with that below. if (secret.empty()) { isc_throw(D2CfgError, "TSIG key must specify secret (" << pos["secret"] << ")"); } // Everything should be valid, so create the key instance. // It is possible for the asiodns::dns::TSIGKey create to fail such as // with an invalid secret content. TSIGKeyInfoPtr key_info; try { key_info.reset(new TSIGKeyInfo(name, algorithm, secret)); } catch (const std::exception& ex) { isc_throw(D2CfgError, ex.what() << " (" << key_config->getPosition() << ")"); } // Add the new TSIGKeyInfo to the key storage. (*keys_)[name]=key_info; } isc::dhcp::ParserPtr TSIGKeyInfoParser::createConfigParser(const std::string& config_id, const isc::data::Element::Position& pos) { 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 << " (" << pos << ")"); } // Return the new parser instance. return (isc::dhcp::ParserPtr(parser)); } void TSIGKeyInfoParser::commit() { } // *********************** TSIGKeyInfoListParser ************************* TSIGKeyInfoListParser::TSIGKeyInfoListParser(const std::string& list_name, TSIGKeyInfoMapPtr keys) :list_name_(list_name), keys_(keys), local_keys_(new TSIGKeyInfoMap()), 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(i++); isc::dhcp::ParserPtr parser(new TSIGKeyInfoParser(entry_name, local_keys_)); parser->build(key_config); parsers_.push_back(parser); } // Now that we know we have a valid list, commit that list to the // area given to us during construction (i.e. to the d2 context). *keys_ = *local_keys_; } 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) : entry_name_(entry_name), servers_(servers), local_scalars_() { if (!servers_) { isc_throw(D2CfgError, "DnsServerInfoParser ctor:" " server storage cannot be null"); } } DnsServerInfoParser::~DnsServerInfoParser() { } 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 // 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, server_config->mapValue()) { isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first, config_pair.second-> getPosition())); parser->build(config_pair.second); parser->commit(); } std::string hostname; std::string ip_address; uint32_t port = DnsServerInfo::STANDARD_DNS_PORT; std::map pos; // Fetch the server configuration's parsed scalar values from parser's // local storage. They're all optional, so no try-catch here. pos["hostname"] = local_scalars_.getParam("hostname", hostname, DCfgContextBase::OPTIONAL); pos["ip_address"] = local_scalars_.getParam("ip_address", ip_address, DCfgContextBase::OPTIONAL); pos["port"] = local_scalars_.getParam("port", port, DCfgContextBase::OPTIONAL); // The configuration must specify one or the other. if (hostname.empty() == ip_address.empty()) { isc_throw(D2CfgError, "Dns Server must specify one or the other" " of hostname or IP address" << " (" << server_config->getPosition() << ")"); } // Port cannot be zero. if (port == 0) { isc_throw(D2CfgError, "Dns Server : port cannot be 0" << " (" << pos["port"] << ")"); } DnsServerInfoPtr serverInfo; if (!hostname.empty()) { /// @todo when resolvable hostname is supported we create the entry /// as follows: /// /// @code /// // When hostname is specified, create a valid, blank IOAddress /// // and then create the DnsServerInfo. /// isc::asiolink::IOAddress io_addr(DnsServerInfo::EMPTY_IP_STR); /// serverInfo.reset(new DnsServerInfo(hostname, io_addr, port)); /// /// @endcode /// /// Resolution will be done prior to connection during transaction /// processing. /// Until then we'll throw unsupported. isc_throw(D2CfgError, "Dns Server : hostname is not yet supported" << " (" << pos["hostname"] << ")"); } else { try { // Create an IOAddress from the IP address string given and then // create the DnsServerInfo. isc::asiolink::IOAddress io_addr(ip_address); serverInfo.reset(new DnsServerInfo(hostname, io_addr, port)); } catch (const isc::asiolink::IOError& ex) { isc_throw(D2CfgError, "Dns Server : invalid IP address : " << ip_address << " (" << pos["ip_address"] << ")"); } } // Add the new DnsServerInfo to the server storage. servers_->push_back(serverInfo); } isc::dhcp::ParserPtr DnsServerInfoParser::createConfigParser(const std::string& config_id, const isc::data::Element:: Position& pos) { 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 == "hostname") || (config_id == "ip_address")) { parser = new isc::dhcp::StringParser(config_id, local_scalars_.getStringStorage()); } 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: " << config_id << " (" << pos << ")"); } // Return the new parser instance. return (isc::dhcp::ParserPtr(parser)); } void DnsServerInfoParser::commit() { } // *********************** DnsServerInfoListParser ************************* DnsServerInfoListParser::DnsServerInfoListParser(const std::string& list_name, DnsServerInfoStoragePtr servers) :list_name_(list_name), servers_(servers), parsers_() { if (!servers_) { isc_throw(D2CfgError, "DdnsServerInfoListParser ctor:" " server storage cannot be null"); } } DnsServerInfoListParser::~DnsServerInfoListParser(){ } void DnsServerInfoListParser:: build(isc::data::ConstElementPtr server_list){ int i = 0; isc::data::ConstElementPtr server_config; // 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 // 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(i++); isc::dhcp::ParserPtr parser(new DnsServerInfoParser(entry_name, servers_)); parser->build(server_config); parsers_.push_back(parser); } // Domains must have at least one server. if (parsers_.size() == 0) { isc_throw (D2CfgError, "Server List must contain at least one server" << " (" << server_list->getPosition() << ")"); } } void DnsServerInfoListParser::commit() { // Invoke commit on each server parser. BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) { parser->commit(); } } // *********************** DdnsDomainParser ************************* DdnsDomainParser::DdnsDomainParser(const std::string& entry_name, DdnsDomainMapPtr domains, TSIGKeyInfoMapPtr keys) : entry_name_(entry_name), domains_(domains), keys_(keys), local_servers_(new DnsServerInfoStorage()), local_scalars_() { if (!domains_) { isc_throw(D2CfgError, "DdnsDomainParser ctor, domain storage cannot be null"); } } DdnsDomainParser::~DdnsDomainParser() { } 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 // configuration. // 3. Invoke the parser's commit method to store the element's parsed // data to the parser's local storage. isc::dhcp::ConfigPair config_pair; BOOST_FOREACH(config_pair, domain_config->mapValue()) { isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first, config_pair.second-> getPosition())); parser->build(config_pair.second); parser->commit(); } // Now construct the domain. std::string name; std::string key_name; std::map pos; // Fetch the parsed scalar values from parser's local storage. // Any required that are missing will throw. try { pos["name"] = local_scalars_.getParam("name", name); pos["key_name"] = local_scalars_.getParam("key_name", key_name, DCfgContextBase::OPTIONAL); } catch (const std::exception& ex) { isc_throw(D2CfgError, "DdnsDomain incomplete : " << ex.what() << " (" << domain_config->getPosition() << ")"); } // Blank domain names are not allowed. if (name.empty()) { isc_throw(D2CfgError, "DndsDomain : name cannot be blank (" << pos["name"] << ")"); } // Currently, the premise is that domain storage is always empty // prior to parsing so always adding domains never replacing them. // 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 << " (" << pos["name"] << ")"); } // Key name is optional. If it is not blank, then find the key in the /// list of defined keys. TSIGKeyInfoPtr tsig_key_info; if (!key_name.empty()) { if (keys_) { TSIGKeyInfoMap::iterator kit = keys_->find(key_name); if (kit != keys_->end()) { tsig_key_info = kit->second; } } if (!tsig_key_info) { isc_throw(D2CfgError, "DdnsDomain : " << name << " specifies an undefined key: " << key_name << " (" << pos["key_name"] << ")"); } } // Instantiate the new domain and add it to domain storage. DdnsDomainPtr domain(new DdnsDomain(name, local_servers_, tsig_key_info)); // Add the new domain to the domain storage. (*domains_)[name] = domain; } isc::dhcp::ParserPtr DdnsDomainParser::createConfigParser(const std::string& config_id, const isc::data::Element::Position& pos) { 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 == "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 // this down to its server parsers and is where they will write their // server instances upon commit. parser = new DnsServerInfoListParser(config_id, local_servers_); } else { isc_throw(NotImplemented, "parser error: DdnsDomain parameter not supported: " << config_id << " (" << pos << ")"); } // Return the new domain parser instance. return (isc::dhcp::ParserPtr(parser)); } void DdnsDomainParser::commit() { } // *********************** DdnsDomainListParser ************************* DdnsDomainListParser::DdnsDomainListParser(const std::string& list_name, 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"); } } DdnsDomainListParser::~DdnsDomainListParser(){ } void DdnsDomainListParser:: build(isc::data::ConstElementPtr 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 // 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(i++); isc::dhcp::ParserPtr parser(new DdnsDomainParser(entry_name, domains_, keys_)); parser->build(domain_config); parsers_.push_back(parser); } } 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. BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) { parser->commit(); } } // *********************** DdnsDomainListMgrParser ************************* DdnsDomainListMgrParser::DdnsDomainListMgrParser(const std::string& entry_name, DdnsDomainListMgrPtr mgr, TSIGKeyInfoMapPtr keys) : entry_name_(entry_name), mgr_(mgr), keys_(keys), local_domains_(new DdnsDomainMap()), local_scalars_() { } DdnsDomainListMgrParser::~DdnsDomainListMgrParser() { } 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 // configuration. // 3. Invoke the parser's commit method to store the element's parsed // data to the parser's local storage. isc::dhcp::ConfigPair config_pair; BOOST_FOREACH(config_pair, domain_config->mapValue()) { isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first, config_pair.second-> getPosition())); parser->build(config_pair.second); parser->commit(); } // Add the new domain to the domain storage. mgr_->setDomains(local_domains_); } isc::dhcp::ParserPtr DdnsDomainListMgrParser::createConfigParser(const std::string& config_id, const isc::data::Element:: Position& pos) { 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_, keys_); } else { isc_throw(NotImplemented, "parser error: " "DdnsDomainListMgr parameter not supported: " << config_id << " (" << pos << ")"); } // Return the new domain parser instance. return (isc::dhcp::ParserPtr(parser)); } void DdnsDomainListMgrParser::commit() { } }; // end of isc::dhcp namespace }; // end of isc namespace