d2_config.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. // Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <d2/d2_log.h>
  15. #include <d2/d2_cfg_mgr.h>
  16. #include <dhcpsrv/dhcp_parsers.h>
  17. #include <exceptions/exceptions.h>
  18. #include <asiolink/io_error.h>
  19. #include <boost/foreach.hpp>
  20. #include <boost/lexical_cast.hpp>
  21. #include <boost/algorithm/string/predicate.hpp>
  22. #include <string>
  23. namespace isc {
  24. namespace d2 {
  25. // *********************** D2Params *************************
  26. const char *D2Params::DFT_IP_ADDRESS = "127.0.0.1";
  27. const size_t D2Params::DFT_PORT = 53001;
  28. const size_t D2Params::DFT_DNS_SERVER_TIMEOUT = 100;
  29. const char *D2Params::DFT_NCR_PROTOCOL = "UDP";
  30. const char *D2Params::DFT_NCR_FORMAT = "JSON";
  31. D2Params::D2Params(const isc::asiolink::IOAddress& ip_address,
  32. const size_t port,
  33. const size_t dns_server_timeout,
  34. const dhcp_ddns::NameChangeProtocol& ncr_protocol,
  35. const dhcp_ddns::NameChangeFormat& ncr_format)
  36. : ip_address_(ip_address),
  37. port_(port),
  38. dns_server_timeout_(dns_server_timeout),
  39. ncr_protocol_(ncr_protocol),
  40. ncr_format_(ncr_format) {
  41. validateContents();
  42. }
  43. D2Params::D2Params()
  44. : ip_address_(isc::asiolink::IOAddress(DFT_IP_ADDRESS)),
  45. port_(DFT_PORT),
  46. dns_server_timeout_(DFT_DNS_SERVER_TIMEOUT),
  47. ncr_protocol_(dhcp_ddns::NCR_UDP),
  48. ncr_format_(dhcp_ddns::FMT_JSON) {
  49. validateContents();
  50. }
  51. D2Params::~D2Params(){};
  52. void
  53. D2Params::validateContents() {
  54. if ((ip_address_.toText() == "0.0.0.0") || (ip_address_.toText() == "::")) {
  55. isc_throw(D2CfgError,
  56. "D2Params: IP address cannot be \"" << ip_address_ << "\"");
  57. }
  58. if (port_ == 0) {
  59. isc_throw(D2CfgError, "D2Params: port cannot be 0");
  60. }
  61. if (dns_server_timeout_ < 1) {
  62. isc_throw(D2CfgError,
  63. "D2Params: DNS server timeout must be larger than 0");
  64. }
  65. if (ncr_format_ != dhcp_ddns::FMT_JSON) {
  66. isc_throw(D2CfgError, "D2Params: NCR Format:"
  67. << dhcp_ddns::ncrFormatToString(ncr_format_)
  68. << " is not yet supported");
  69. }
  70. if (ncr_protocol_ != dhcp_ddns::NCR_UDP) {
  71. isc_throw(D2CfgError, "D2Params: NCR Protocol:"
  72. << dhcp_ddns::ncrProtocolToString(ncr_protocol_)
  73. << " is not yet supported");
  74. }
  75. }
  76. bool
  77. D2Params::operator == (const D2Params& other) const {
  78. return ((ip_address_ == other.ip_address_) &&
  79. (port_ == other.port_) &&
  80. (dns_server_timeout_ == other.dns_server_timeout_) &&
  81. (ncr_protocol_ == other.ncr_protocol_) &&
  82. (ncr_format_ == other.ncr_format_));
  83. }
  84. bool
  85. D2Params::operator != (const D2Params& other) const {
  86. return (!(*this == other));
  87. }
  88. std::string
  89. D2Params::toText() const {
  90. std::ostringstream stream;
  91. stream << ", ip_address: " << ip_address_.toText()
  92. << ", port: " << port_
  93. << ", dns_server_timeout_: " << dns_server_timeout_
  94. << ", ncr_protocol: "
  95. << dhcp_ddns::ncrProtocolToString(ncr_protocol_)
  96. << ", ncr_format: " << ncr_format_
  97. << dhcp_ddns::ncrFormatToString(ncr_format_);
  98. return (stream.str());
  99. }
  100. std::ostream&
  101. operator<<(std::ostream& os, const D2Params& config) {
  102. os << config.toText();
  103. return (os);
  104. }
  105. // *********************** TSIGKeyInfo *************************
  106. // Note these values match correpsonding values for Bind9's
  107. // dnssec-keygen
  108. const char* TSIGKeyInfo::HMAC_MD5_STR = "HMAC-MD5";
  109. const char* TSIGKeyInfo::HMAC_SHA1_STR = "HMAC-SHA1";
  110. const char* TSIGKeyInfo::HMAC_SHA224_STR = "HMAC-SHA224";
  111. const char* TSIGKeyInfo::HMAC_SHA256_STR = "HMAC-SHA256";
  112. const char* TSIGKeyInfo::HMAC_SHA384_STR = "HMAC-SHA384";
  113. const char* TSIGKeyInfo::HMAC_SHA512_STR = "HMAC-SHA512";
  114. TSIGKeyInfo::TSIGKeyInfo(const std::string& name, const std::string& algorithm,
  115. const std::string& secret)
  116. :name_(name), algorithm_(algorithm), secret_(secret), tsig_key_() {
  117. remakeKey();
  118. }
  119. TSIGKeyInfo::~TSIGKeyInfo() {
  120. }
  121. const dns::Name&
  122. TSIGKeyInfo::stringToAlgorithmName(const std::string& algorithm_id) {
  123. if (boost::iequals(algorithm_id, HMAC_MD5_STR)) {
  124. return (dns::TSIGKey::HMACMD5_NAME());
  125. } else if (boost::iequals(algorithm_id, HMAC_SHA1_STR)) {
  126. return (dns::TSIGKey::HMACSHA1_NAME());
  127. } else if (boost::iequals(algorithm_id, HMAC_SHA224_STR)) {
  128. return (dns::TSIGKey::HMACSHA224_NAME());
  129. } else if (boost::iequals(algorithm_id, HMAC_SHA256_STR)) {
  130. return (dns::TSIGKey::HMACSHA256_NAME());
  131. } else if (boost::iequals(algorithm_id, HMAC_SHA384_STR)) {
  132. return (dns::TSIGKey::HMACSHA384_NAME());
  133. } else if (boost::iequals(algorithm_id, HMAC_SHA512_STR)) {
  134. return (dns::TSIGKey::HMACSHA512_NAME());
  135. }
  136. isc_throw(BadValue, "Unknown TSIG Key algorithm: " << algorithm_id);
  137. }
  138. void
  139. TSIGKeyInfo::remakeKey() {
  140. try {
  141. // Since our secret value is base64 encoded already, we need to
  142. // build the input string for the appropriate TSIGKey constructor.
  143. // If secret isn't a valid base64 value, the constructor will throw.
  144. std::ostringstream stream;
  145. stream << dns::Name(name_).toText() << ":"
  146. << secret_ << ":"
  147. << stringToAlgorithmName(algorithm_);
  148. tsig_key_.reset(new dns::TSIGKey(stream.str()));
  149. } catch (const std::exception& ex) {
  150. isc_throw(D2CfgError, "Cannot make TSIGKey: " << ex.what());
  151. }
  152. }
  153. // *********************** DnsServerInfo *************************
  154. const char* DnsServerInfo::EMPTY_IP_STR = "0.0.0.0";
  155. DnsServerInfo::DnsServerInfo(const std::string& hostname,
  156. isc::asiolink::IOAddress ip_address, uint32_t port,
  157. bool enabled)
  158. :hostname_(hostname), ip_address_(ip_address), port_(port),
  159. enabled_(enabled) {
  160. }
  161. DnsServerInfo::~DnsServerInfo() {
  162. }
  163. std::string
  164. DnsServerInfo::toText() const {
  165. std::ostringstream stream;
  166. stream << (getIpAddress().toText()) << " port:" << getPort();
  167. return (stream.str());
  168. }
  169. std::ostream&
  170. operator<<(std::ostream& os, const DnsServerInfo& server) {
  171. os << server.toText();
  172. return (os);
  173. }
  174. // *********************** DdnsDomain *************************
  175. DdnsDomain::DdnsDomain(const std::string& name,
  176. DnsServerInfoStoragePtr servers,
  177. const TSIGKeyInfoPtr& tsig_key_info)
  178. : name_(name), servers_(servers),
  179. tsig_key_info_(tsig_key_info) {
  180. }
  181. DdnsDomain::~DdnsDomain() {
  182. }
  183. const std::string
  184. DdnsDomain::getKeyName() const {
  185. if (tsig_key_info_) {
  186. return (tsig_key_info_->getName());
  187. }
  188. return ("");
  189. }
  190. // *********************** DdnsDomainLstMgr *************************
  191. const char* DdnsDomainListMgr::wildcard_domain_name_ = "*";
  192. DdnsDomainListMgr::DdnsDomainListMgr(const std::string& name) : name_(name),
  193. domains_(new DdnsDomainMap()) {
  194. }
  195. DdnsDomainListMgr::~DdnsDomainListMgr () {
  196. }
  197. void
  198. DdnsDomainListMgr::setDomains(DdnsDomainMapPtr domains) {
  199. if (!domains) {
  200. isc_throw(D2CfgError,
  201. "DdnsDomainListMgr::setDomains: Domain list may not be null");
  202. }
  203. domains_ = domains;
  204. // Look for the wild card domain. If present, set the member variable
  205. // to remember it. This saves us from having to look for it every time
  206. // we attempt a match.
  207. DdnsDomainMap::iterator gotit = domains_->find(wildcard_domain_name_);
  208. if (gotit != domains_->end()) {
  209. wildcard_domain_ = gotit->second;
  210. }
  211. }
  212. bool
  213. DdnsDomainListMgr::matchDomain(const std::string& fqdn, DdnsDomainPtr& domain) {
  214. // First check the case of one domain to rule them all.
  215. if ((size() == 1) && (wildcard_domain_)) {
  216. domain = wildcard_domain_;
  217. return (true);
  218. }
  219. // Iterate over the domain map looking for the domain which matches
  220. // the longest portion of the given fqdn.
  221. size_t req_len = fqdn.size();
  222. size_t match_len = 0;
  223. DdnsDomainMapPair map_pair;
  224. DdnsDomainPtr best_match;
  225. BOOST_FOREACH (map_pair, *domains_) {
  226. std::string domain_name = map_pair.first;
  227. size_t dom_len = domain_name.size();
  228. // If the domain name is longer than the fqdn, then it cant be match.
  229. if (req_len < dom_len) {
  230. continue;
  231. }
  232. // If the lengths are identical and the names match we're done.
  233. if (req_len == dom_len) {
  234. if (boost::iequals(fqdn, domain_name)) {
  235. // exact match, done
  236. domain = map_pair.second;
  237. return (true);
  238. }
  239. } else {
  240. // The fqdn is longer than the domain name. Adjust the start
  241. // point of comparison by the excess in length. Only do the
  242. // comparison if the adjustment lands on a boundary. This
  243. // prevents "onetwo.net" from matching "two.net".
  244. size_t offset = req_len - dom_len;
  245. if ((fqdn[offset - 1] == '.') &&
  246. (boost::iequals(fqdn.substr(offset), domain_name))) {
  247. // Fqdn contains domain name, keep it if its better than
  248. // any we have matched so far.
  249. if (dom_len > match_len) {
  250. match_len = dom_len;
  251. best_match = map_pair.second;
  252. }
  253. }
  254. }
  255. }
  256. if (!best_match) {
  257. // There's no match. If they specified a wild card domain use it
  258. // otherwise there's no domain for this entry.
  259. if (wildcard_domain_) {
  260. domain = wildcard_domain_;
  261. return (true);
  262. }
  263. LOG_WARN(dctl_logger, DHCP_DDNS_NO_MATCH).arg(fqdn);
  264. return (false);
  265. }
  266. domain = best_match;
  267. return (true);
  268. }
  269. // *************************** PARSERS ***********************************
  270. // *********************** TSIGKeyInfoParser *************************
  271. TSIGKeyInfoParser::TSIGKeyInfoParser(const std::string& entry_name,
  272. TSIGKeyInfoMapPtr keys)
  273. : entry_name_(entry_name), keys_(keys), local_scalars_() {
  274. if (!keys_) {
  275. isc_throw(D2CfgError, "TSIGKeyInfoParser ctor:"
  276. " key storage cannot be null");
  277. }
  278. }
  279. TSIGKeyInfoParser::~TSIGKeyInfoParser() {
  280. }
  281. void
  282. TSIGKeyInfoParser::build(isc::data::ConstElementPtr key_config) {
  283. isc::dhcp::ConfigPair config_pair;
  284. // For each element in the key configuration:
  285. // 1. Create a parser for the element.
  286. // 2. Invoke the parser's build method passing in the element's
  287. // configuration.
  288. // 3. Invoke the parser's commit method to store the element's parsed
  289. // data to the parser's local storage.
  290. BOOST_FOREACH (config_pair, key_config->mapValue()) {
  291. isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first));
  292. parser->build(config_pair.second);
  293. parser->commit();
  294. }
  295. std::string name;
  296. std::string algorithm;
  297. std::string secret;
  298. std::vector<isc::data::Element::Position> pos;
  299. // Fetch the key's parsed scalar values from parser's local storage.
  300. // All are required, if any are missing we'll throw.
  301. try {
  302. pos.push_back(local_scalars_.getParam("name", name));
  303. pos.push_back(local_scalars_.getParam("algorithm", algorithm));
  304. pos.push_back(local_scalars_.getParam("secret", secret));
  305. } catch (const std::exception& ex) {
  306. isc_throw(D2CfgError, "TSIG Key incomplete : " << ex.what()
  307. << " : " << key_config->getPosition());
  308. }
  309. // Name cannot be blank.
  310. if (name.empty()) {
  311. isc_throw(D2CfgError, "TSIG key must specify name : " << pos[0]);
  312. }
  313. // Currently, the premise is that key storage is always empty prior to
  314. // parsing so we are always adding keys never replacing them. Duplicates
  315. // are not allowed and should be flagged as a configuration error.
  316. if (keys_->find(name) != keys_->end()) {
  317. isc_throw(D2CfgError, "Duplicate TSIG key name specified : " << name
  318. << " : " << pos[0]);
  319. }
  320. // Algorithm must be valid.
  321. try {
  322. TSIGKeyInfo::stringToAlgorithmName(algorithm);
  323. } catch (const std::exception& ex) {
  324. isc_throw(D2CfgError, "TSIG key invalid algorithm : "
  325. << algorithm << " : " << pos[1]);
  326. }
  327. // Secret cannot be blank.
  328. // Cryptolink lib doesn't offer anyway to validate these. As long as it
  329. // isn't blank we'll accept it. If the content is bad, the call to in
  330. // TSIGKeyInfo::remakeKey() made in the TSIGKeyInfo ctor will throw.
  331. // We'll deal with that below.
  332. if (secret.empty()) {
  333. isc_throw(D2CfgError, "TSIG key must specify secret : " << pos[2]);
  334. }
  335. // Everything should be valid, so create the key instance.
  336. // It is possible for the asiodns::dns::TSIGKey create to fail such as
  337. // with an invalid secret content.
  338. TSIGKeyInfoPtr key_info;
  339. try {
  340. key_info.reset(new TSIGKeyInfo(name, algorithm, secret));
  341. } catch (const std::exception& ex) {
  342. isc_throw(D2CfgError, ex.what() << " : " << key_config->getPosition());
  343. }
  344. // Add the new TSIGKeyInfo to the key storage.
  345. (*keys_)[name]=key_info;
  346. }
  347. isc::dhcp::ParserPtr
  348. TSIGKeyInfoParser::createConfigParser(const std::string& config_id) {
  349. DhcpConfigParser* parser = NULL;
  350. // Based on the configuration id of the element, create the appropriate
  351. // parser. Scalars are set to use the parser's local scalar storage.
  352. if ((config_id == "name") ||
  353. (config_id == "algorithm") ||
  354. (config_id == "secret")) {
  355. parser = new isc::dhcp::StringParser(config_id,
  356. local_scalars_.getStringStorage());
  357. } else {
  358. isc_throw(NotImplemented,
  359. "parser error: TSIGKeyInfo parameter not supported: "
  360. << config_id);
  361. }
  362. // Return the new parser instance.
  363. return (isc::dhcp::ParserPtr(parser));
  364. }
  365. void
  366. TSIGKeyInfoParser::commit() {
  367. }
  368. // *********************** TSIGKeyInfoListParser *************************
  369. TSIGKeyInfoListParser::TSIGKeyInfoListParser(const std::string& list_name,
  370. TSIGKeyInfoMapPtr keys)
  371. :list_name_(list_name), keys_(keys), local_keys_(new TSIGKeyInfoMap()),
  372. parsers_() {
  373. if (!keys_) {
  374. isc_throw(D2CfgError, "TSIGKeyInfoListParser ctor:"
  375. " key storage cannot be null");
  376. }
  377. }
  378. TSIGKeyInfoListParser::~TSIGKeyInfoListParser() {
  379. }
  380. void
  381. TSIGKeyInfoListParser::
  382. build(isc::data::ConstElementPtr key_list) {
  383. int i = 0;
  384. isc::data::ConstElementPtr key_config;
  385. // For each key element in the key list:
  386. // 1. Create a parser for the key element.
  387. // 2. Invoke the parser's build method passing in the key's
  388. // configuration.
  389. // 3. Add the parser to a local collection of parsers.
  390. BOOST_FOREACH(key_config, key_list->listValue()) {
  391. // Create a name for the parser based on its position in the list.
  392. std::string entry_name = boost::lexical_cast<std::string>(i++);
  393. isc::dhcp::ParserPtr parser(new TSIGKeyInfoParser(entry_name,
  394. local_keys_));
  395. parser->build(key_config);
  396. parsers_.push_back(parser);
  397. }
  398. // Now that we know we have a valid list, commit that list to the
  399. // area given to us during construction (i.e. to the d2 context).
  400. *keys_ = *local_keys_;
  401. }
  402. void
  403. TSIGKeyInfoListParser::commit() {
  404. // Invoke commit on each server parser. This will cause each one to
  405. // create it's server instance and commit it to storage.
  406. BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
  407. parser->commit();
  408. }
  409. }
  410. // *********************** DnsServerInfoParser *************************
  411. DnsServerInfoParser::DnsServerInfoParser(const std::string& entry_name,
  412. DnsServerInfoStoragePtr servers)
  413. : entry_name_(entry_name), servers_(servers), local_scalars_() {
  414. if (!servers_) {
  415. isc_throw(D2CfgError, "DnsServerInfoParser ctor:"
  416. " server storage cannot be null");
  417. }
  418. }
  419. DnsServerInfoParser::~DnsServerInfoParser() {
  420. }
  421. void
  422. DnsServerInfoParser::build(isc::data::ConstElementPtr server_config) {
  423. isc::dhcp::ConfigPair config_pair;
  424. // For each element in the server configuration:
  425. // 1. Create a parser for the element.
  426. // 2. Invoke the parser's build method passing in the element's
  427. // configuration.
  428. // 3. Invoke the parser's commit method to store the element's parsed
  429. // data to the parser's local storage.
  430. BOOST_FOREACH (config_pair, server_config->mapValue()) {
  431. isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first));
  432. parser->build(config_pair.second);
  433. parser->commit();
  434. }
  435. std::string hostname;
  436. std::string ip_address;
  437. uint32_t port = DnsServerInfo::STANDARD_DNS_PORT;
  438. // Fetch the server configuration's parsed scalar values from parser's
  439. // local storage.
  440. local_scalars_.getParam("hostname", hostname, DCfgContextBase::OPTIONAL);
  441. local_scalars_.getParam("ip_address", ip_address,
  442. DCfgContextBase::OPTIONAL);
  443. local_scalars_.getParam("port", port, DCfgContextBase::OPTIONAL);
  444. // The configuration must specify one or the other.
  445. if (hostname.empty() == ip_address.empty()) {
  446. isc_throw(D2CfgError, "Dns Server must specify one or the other"
  447. " of hostname and IP address");
  448. }
  449. DnsServerInfoPtr serverInfo;
  450. if (!hostname.empty()) {
  451. // When hostname is specified, create a valid, blank IOAddress and
  452. // then create the DnsServerInfo.
  453. isc::asiolink::IOAddress io_addr(DnsServerInfo::EMPTY_IP_STR);
  454. serverInfo.reset(new DnsServerInfo(hostname, io_addr, port));
  455. } else {
  456. try {
  457. // Create an IOAddress from the IP address string given and then
  458. // create the DnsServerInfo.
  459. isc::asiolink::IOAddress io_addr(ip_address);
  460. serverInfo.reset(new DnsServerInfo(hostname, io_addr, port));
  461. } catch (const isc::asiolink::IOError& ex) {
  462. isc_throw(D2CfgError, "Invalid IP address:" << ip_address);
  463. }
  464. }
  465. // Add the new DnsServerInfo to the server storage.
  466. servers_->push_back(serverInfo);
  467. }
  468. isc::dhcp::ParserPtr
  469. DnsServerInfoParser::createConfigParser(const std::string& config_id) {
  470. DhcpConfigParser* parser = NULL;
  471. // Based on the configuration id of the element, create the appropriate
  472. // parser. Scalars are set to use the parser's local scalar storage.
  473. if ((config_id == "hostname") ||
  474. (config_id == "ip_address")) {
  475. parser = new isc::dhcp::StringParser(config_id,
  476. local_scalars_.getStringStorage());
  477. } else if (config_id == "port") {
  478. parser = new isc::dhcp::Uint32Parser(config_id,
  479. local_scalars_.getUint32Storage());
  480. } else {
  481. isc_throw(NotImplemented,
  482. "parser error: DnsServerInfo parameter not supported: "
  483. << config_id);
  484. }
  485. // Return the new parser instance.
  486. return (isc::dhcp::ParserPtr(parser));
  487. }
  488. void
  489. DnsServerInfoParser::commit() {
  490. }
  491. // *********************** DnsServerInfoListParser *************************
  492. DnsServerInfoListParser::DnsServerInfoListParser(const std::string& list_name,
  493. DnsServerInfoStoragePtr servers)
  494. :list_name_(list_name), servers_(servers), parsers_() {
  495. if (!servers_) {
  496. isc_throw(D2CfgError, "DdnsServerInfoListParser ctor:"
  497. " server storage cannot be null");
  498. }
  499. }
  500. DnsServerInfoListParser::~DnsServerInfoListParser(){
  501. }
  502. void
  503. DnsServerInfoListParser::
  504. build(isc::data::ConstElementPtr server_list){
  505. int i = 0;
  506. isc::data::ConstElementPtr server_config;
  507. // For each server element in the server list:
  508. // 1. Create a parser for the server element.
  509. // 2. Invoke the parser's build method passing in the server's
  510. // configuration.
  511. // 3. Add the parser to a local collection of parsers.
  512. BOOST_FOREACH(server_config, server_list->listValue()) {
  513. // Create a name for the parser based on its position in the list.
  514. std::string entry_name = boost::lexical_cast<std::string>(i++);
  515. isc::dhcp::ParserPtr parser(new DnsServerInfoParser(entry_name,
  516. servers_));
  517. parser->build(server_config);
  518. parsers_.push_back(parser);
  519. }
  520. // Domains must have at least one server.
  521. if (parsers_.size() == 0) {
  522. isc_throw (D2CfgError, "Server List must contain at least one server");
  523. }
  524. }
  525. void
  526. DnsServerInfoListParser::commit() {
  527. // Invoke commit on each server parser.
  528. BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
  529. parser->commit();
  530. }
  531. }
  532. // *********************** DdnsDomainParser *************************
  533. DdnsDomainParser::DdnsDomainParser(const std::string& entry_name,
  534. DdnsDomainMapPtr domains,
  535. TSIGKeyInfoMapPtr keys)
  536. : entry_name_(entry_name), domains_(domains), keys_(keys),
  537. local_servers_(new DnsServerInfoStorage()), local_scalars_() {
  538. if (!domains_) {
  539. isc_throw(D2CfgError,
  540. "DdnsDomainParser ctor, domain storage cannot be null");
  541. }
  542. }
  543. DdnsDomainParser::~DdnsDomainParser() {
  544. }
  545. void
  546. DdnsDomainParser::build(isc::data::ConstElementPtr domain_config) {
  547. // For each element in the domain configuration:
  548. // 1. Create a parser for the element.
  549. // 2. Invoke the parser's build method passing in the element's
  550. // configuration.
  551. // 3. Invoke the parser's commit method to store the element's parsed
  552. // data to the parser's local storage.
  553. isc::dhcp::ConfigPair config_pair;
  554. BOOST_FOREACH(config_pair, domain_config->mapValue()) {
  555. isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first));
  556. parser->build(config_pair.second);
  557. parser->commit();
  558. }
  559. // Now construct the domain.
  560. std::string name;
  561. std::string key_name;
  562. // Domain name is not optional. The get will throw if its not there.
  563. local_scalars_.getParam("name", name);
  564. // Blank domain names are not allowed.
  565. if (name.empty()) {
  566. isc_throw(D2CfgError, "Domain name cannot be blank");
  567. }
  568. // Currently, the premise is that domain storage is always empty
  569. // prior to parsing so always adding domains never replacing them.
  570. // Duplicates are not allowed and should be flagged as a configuration
  571. // error.
  572. if (domains_->find(name) != domains_->end()) {
  573. isc_throw(D2CfgError, "Duplicate domain specified:" << name);
  574. }
  575. // Key name is optional. If it is not blank, then find the key in the
  576. /// list of defined keys.
  577. TSIGKeyInfoPtr tsig_key_info;
  578. local_scalars_.getParam("key_name", key_name, DCfgContextBase::OPTIONAL);
  579. if (!key_name.empty()) {
  580. if (keys_) {
  581. TSIGKeyInfoMap::iterator kit = keys_->find(key_name);
  582. if (kit != keys_->end()) {
  583. tsig_key_info = kit->second;
  584. }
  585. }
  586. if (!tsig_key_info) {
  587. isc_throw(D2CfgError, "DdnsDomain " << name <<
  588. " specifies an undefined key: " << key_name);
  589. }
  590. }
  591. // Instantiate the new domain and add it to domain storage.
  592. DdnsDomainPtr domain(new DdnsDomain(name, local_servers_, tsig_key_info));
  593. // Add the new domain to the domain storage.
  594. (*domains_)[name] = domain;
  595. }
  596. isc::dhcp::ParserPtr
  597. DdnsDomainParser::createConfigParser(const std::string& config_id) {
  598. DhcpConfigParser* parser = NULL;
  599. // Based on the configuration id of the element, create the appropriate
  600. // parser. Scalars are set to use the parser's local scalar storage.
  601. if ((config_id == "name") ||
  602. (config_id == "key_name")) {
  603. parser = new isc::dhcp::StringParser(config_id,
  604. local_scalars_.getStringStorage());
  605. } else if (config_id == "dns_servers") {
  606. // Server list parser is given in our local server storage. It will pass
  607. // this down to its server parsers and is where they will write their
  608. // server instances upon commit.
  609. parser = new DnsServerInfoListParser(config_id, local_servers_);
  610. } else {
  611. isc_throw(NotImplemented,
  612. "parser error: DdnsDomain parameter not supported: "
  613. << config_id);
  614. }
  615. // Return the new domain parser instance.
  616. return (isc::dhcp::ParserPtr(parser));
  617. }
  618. void
  619. DdnsDomainParser::commit() {
  620. }
  621. // *********************** DdnsDomainListParser *************************
  622. DdnsDomainListParser::DdnsDomainListParser(const std::string& list_name,
  623. DdnsDomainMapPtr domains,
  624. TSIGKeyInfoMapPtr keys)
  625. :list_name_(list_name), domains_(domains), keys_(keys), parsers_() {
  626. if (!domains_) {
  627. isc_throw(D2CfgError, "DdnsDomainListParser ctor:"
  628. " domain storage cannot be null");
  629. }
  630. }
  631. DdnsDomainListParser::~DdnsDomainListParser(){
  632. }
  633. void
  634. DdnsDomainListParser::
  635. build(isc::data::ConstElementPtr domain_list){
  636. // For each domain element in the domain list:
  637. // 1. Create a parser for the domain element.
  638. // 2. Invoke the parser's build method passing in the domain's
  639. // configuration.
  640. // 3. Add the parser to the local collection of parsers.
  641. int i = 0;
  642. isc::data::ConstElementPtr domain_config;
  643. BOOST_FOREACH(domain_config, domain_list->listValue()) {
  644. std::string entry_name = boost::lexical_cast<std::string>(i++);
  645. isc::dhcp::ParserPtr parser(new DdnsDomainParser(entry_name,
  646. domains_, keys_));
  647. parser->build(domain_config);
  648. parsers_.push_back(parser);
  649. }
  650. }
  651. void
  652. DdnsDomainListParser::commit() {
  653. // Invoke commit on each server parser. This will cause each one to
  654. // create it's server instance and commit it to storage.
  655. BOOST_FOREACH(isc::dhcp::ParserPtr parser, parsers_) {
  656. parser->commit();
  657. }
  658. }
  659. // *********************** DdnsDomainListMgrParser *************************
  660. DdnsDomainListMgrParser::DdnsDomainListMgrParser(const std::string& entry_name,
  661. DdnsDomainListMgrPtr mgr, TSIGKeyInfoMapPtr keys)
  662. : entry_name_(entry_name), mgr_(mgr), keys_(keys),
  663. local_domains_(new DdnsDomainMap()), local_scalars_() {
  664. }
  665. DdnsDomainListMgrParser::~DdnsDomainListMgrParser() {
  666. }
  667. void
  668. DdnsDomainListMgrParser::build(isc::data::ConstElementPtr domain_config) {
  669. // For each element in the domain manager configuration:
  670. // 1. Create a parser for the element.
  671. // 2. Invoke the parser's build method passing in the element's
  672. // configuration.
  673. // 3. Invoke the parser's commit method to store the element's parsed
  674. // data to the parser's local storage.
  675. isc::dhcp::ConfigPair config_pair;
  676. BOOST_FOREACH(config_pair, domain_config->mapValue()) {
  677. isc::dhcp::ParserPtr parser(createConfigParser(config_pair.first));
  678. parser->build(config_pair.second);
  679. parser->commit();
  680. }
  681. // Add the new domain to the domain storage.
  682. mgr_->setDomains(local_domains_);
  683. }
  684. isc::dhcp::ParserPtr
  685. DdnsDomainListMgrParser::createConfigParser(const std::string& config_id) {
  686. DhcpConfigParser* parser = NULL;
  687. if (config_id == "ddns_domains") {
  688. // Domain list parser is given our local domain storage. It will pass
  689. // this down to its domain parsers and is where they will write their
  690. // domain instances upon commit.
  691. parser = new DdnsDomainListParser(config_id, local_domains_, keys_);
  692. } else {
  693. isc_throw(NotImplemented, "parser error: "
  694. "DdnsDomainListMgr parameter not supported: " << config_id);
  695. }
  696. // Return the new domain parser instance.
  697. return (isc::dhcp::ParserPtr(parser));
  698. }
  699. void
  700. DdnsDomainListMgrParser::commit() {
  701. }
  702. }; // end of isc::dhcp namespace
  703. }; // end of isc namespace