json_config_parser.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. // Copyright (C) 2012-2015 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 <config.h>
  15. #include <cc/command_interpreter.h>
  16. #include <dhcp4/dhcp4_log.h>
  17. #include <dhcp/libdhcp++.h>
  18. #include <dhcp/option_definition.h>
  19. #include <dhcpsrv/cfg_option.h>
  20. #include <dhcpsrv/cfgmgr.h>
  21. #include <dhcp4/json_config_parser.h>
  22. #include <dhcpsrv/option_space_container.h>
  23. #include <dhcpsrv/parsers/dbaccess_parser.h>
  24. #include <dhcpsrv/parsers/dhcp_parsers.h>
  25. #include <dhcpsrv/parsers/host_reservation_parser.h>
  26. #include <dhcpsrv/parsers/host_reservations_list_parser.h>
  27. #include <dhcpsrv/parsers/ifaces_config_parser.h>
  28. #include <config/command_mgr.h>
  29. #include <util/encode/hex.h>
  30. #include <util/strutil.h>
  31. #include <boost/foreach.hpp>
  32. #include <boost/lexical_cast.hpp>
  33. #include <boost/algorithm/string.hpp>
  34. #include <limits>
  35. #include <iostream>
  36. #include <vector>
  37. #include <map>
  38. using namespace std;
  39. using namespace isc;
  40. using namespace isc::dhcp;
  41. using namespace isc::data;
  42. using namespace isc::asiolink;
  43. namespace {
  44. /// @brief Parser for IPv4 pool definitions.
  45. ///
  46. /// This is the IPv4 derivation of the PoolParser class and handles pool
  47. /// definitions, i.e. a list of entries of one of two syntaxes: min-max and
  48. /// prefix/len for IPv4 pools. Pool4 objects are created and stored in chosen
  49. /// PoolStorage container.
  50. ///
  51. /// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
  52. class Pool4Parser : public PoolParser {
  53. public:
  54. /// @brief Constructor.
  55. ///
  56. /// @param param_name name of the parameter. Note, it is passed through
  57. /// but unused, parameter is currently always "Dhcp4/subnet4[X]/pool"
  58. /// @param pools storage container in which to store the parsed pool
  59. /// upon "commit"
  60. Pool4Parser(const std::string& param_name, PoolStoragePtr pools)
  61. :PoolParser(param_name, pools) {
  62. }
  63. protected:
  64. /// @brief Creates a Pool4 object given a IPv4 prefix and the prefix length.
  65. ///
  66. /// @param addr is the IPv4 prefix of the pool.
  67. /// @param len is the prefix length.
  68. /// @param ignored dummy parameter to provide symmetry between the
  69. /// PoolParser derivations. The V6 derivation requires a third value.
  70. /// @return returns a PoolPtr to the new Pool4 object.
  71. PoolPtr poolMaker (IOAddress &addr, uint32_t len, int32_t) {
  72. return (PoolPtr(new Pool4(addr, len)));
  73. }
  74. /// @brief Creates a Pool4 object given starting and ending IPv4 addresses.
  75. ///
  76. /// @param min is the first IPv4 address in the pool.
  77. /// @param max is the last IPv4 address in the pool.
  78. /// @param ignored dummy parameter to provide symmetry between the
  79. /// PoolParser derivations. The V6 derivation requires a third value.
  80. /// @return returns a PoolPtr to the new Pool4 object.
  81. PoolPtr poolMaker (IOAddress &min, IOAddress &max, int32_t) {
  82. return (PoolPtr(new Pool4(min, max)));
  83. }
  84. };
  85. class Pools4ListParser : public PoolsListParser {
  86. public:
  87. Pools4ListParser(const std::string& dummy, PoolStoragePtr pools)
  88. :PoolsListParser(dummy, pools) {
  89. }
  90. protected:
  91. virtual ParserPtr poolParserMaker(PoolStoragePtr storage) {
  92. return (ParserPtr(new Pool4Parser("pool", storage)));
  93. }
  94. };
  95. /// @brief This class parses a single IPv4 subnet.
  96. ///
  97. /// This is the IPv4 derivation of the SubnetConfigParser class and it parses
  98. /// the whole subnet definition. It creates parsersfor received configuration
  99. /// parameters as needed.
  100. class Subnet4ConfigParser : public SubnetConfigParser {
  101. public:
  102. /// @brief Constructor
  103. ///
  104. /// @param ignored first parameter
  105. /// stores global scope parameters, options, option definitions.
  106. Subnet4ConfigParser(const std::string&)
  107. :SubnetConfigParser("", globalContext(), IOAddress("0.0.0.0")) {
  108. }
  109. /// @brief Parses a single IPv4 subnet configuration and adds to the
  110. /// Configuration Manager.
  111. ///
  112. /// @param subnet A new subnet being configured.
  113. void build(ConstElementPtr subnet) {
  114. SubnetConfigParser::build(subnet);
  115. if (subnet_) {
  116. Subnet4Ptr sub4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
  117. if (!sub4ptr) {
  118. // If we hit this, it is a programming error.
  119. isc_throw(Unexpected,
  120. "Invalid cast in Subnet4ConfigParser::commit");
  121. }
  122. // Set relay information if it was parsed
  123. if (relay_info_) {
  124. sub4ptr->setRelayInfo(*relay_info_);
  125. }
  126. // Adding a subnet to the Configuration Manager may fail if the
  127. // subnet id is invalid (duplicate). Thus, we catch exceptions
  128. // here to append a position in the configuration string.
  129. try {
  130. CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(sub4ptr);
  131. } catch (const std::exception& ex) {
  132. isc_throw(DhcpConfigError, ex.what() << " ("
  133. << subnet->getPosition() << ")");
  134. }
  135. }
  136. // Parse Host Reservations for this subnet if any.
  137. ConstElementPtr reservations = subnet->get("reservations");
  138. if (reservations) {
  139. ParserPtr parser(new HostReservationsListParser<
  140. HostReservationParser4>(subnet_->getID()));
  141. parser->build(reservations);
  142. }
  143. }
  144. /// @brief Commits subnet configuration.
  145. ///
  146. /// This function is currently no-op because subnet should already
  147. /// be added into the Config Manager in the build().
  148. void commit() { }
  149. protected:
  150. /// @brief Creates parsers for entries in subnet definition.
  151. ///
  152. /// @param config_id name of the entry
  153. ///
  154. /// @return parser object for specified entry name. Note the caller is
  155. /// responsible for deleting the parser created.
  156. /// @throw isc::dhcp::DhcpConfigError if trying to create a parser
  157. /// for unknown config element
  158. DhcpConfigParser* createSubnetConfigParser(const std::string& config_id) {
  159. DhcpConfigParser* parser = NULL;
  160. if ((config_id.compare("valid-lifetime") == 0) ||
  161. (config_id.compare("renew-timer") == 0) ||
  162. (config_id.compare("rebind-timer") == 0) ||
  163. (config_id.compare("id") == 0)) {
  164. parser = new Uint32Parser(config_id, uint32_values_);
  165. } else if ((config_id.compare("subnet") == 0) ||
  166. (config_id.compare("interface") == 0) ||
  167. (config_id.compare("client-class") == 0) ||
  168. (config_id.compare("next-server") == 0) ||
  169. (config_id.compare("reservation-mode") == 0)) {
  170. parser = new StringParser(config_id, string_values_);
  171. } else if (config_id.compare("pools") == 0) {
  172. parser = new Pools4ListParser(config_id, pools_);
  173. } else if (config_id.compare("relay") == 0) {
  174. parser = new RelayInfoParser(config_id, relay_info_, Option::V4);
  175. } else if (config_id.compare("option-data") == 0) {
  176. parser = new OptionDataListParser(config_id, options_, AF_INET);
  177. } else if (config_id.compare("match-client-id") == 0) {
  178. parser = new BooleanParser(config_id, boolean_values_);
  179. } else {
  180. isc_throw(NotImplemented, "unsupported parameter: " << config_id);
  181. }
  182. return (parser);
  183. }
  184. /// @brief Issues a DHCP4 server specific warning regarding duplicate subnet
  185. /// options.
  186. ///
  187. /// @param code is the numeric option code of the duplicate option
  188. /// @param addr is the subnet address
  189. /// @todo a means to know the correct logger and perhaps a common
  190. /// message would allow this method to be emitted by the base class.
  191. virtual void duplicate_option_warning(uint32_t code,
  192. isc::asiolink::IOAddress& addr) {
  193. LOG_WARN(dhcp4_logger, DHCP4_CONFIG_OPTION_DUPLICATE)
  194. .arg(code).arg(addr.toText());
  195. }
  196. /// @brief Instantiates the IPv4 Subnet based on a given IPv4 address
  197. /// and prefix length.
  198. ///
  199. /// @param addr is IPv4 address of the subnet.
  200. /// @param len is the prefix length
  201. void initSubnet(isc::asiolink::IOAddress addr, uint8_t len) {
  202. // The renew-timer and rebind-timer are optional. If not set, the
  203. // option 58 and 59 will not be sent to a client. In this case the
  204. // client will use default values based on the valid-lifetime.
  205. Triplet<uint32_t> t1 = getOptionalParam("renew-timer");
  206. Triplet<uint32_t> t2 = getOptionalParam("rebind-timer");
  207. // The valid-lifetime is mandatory. It may be specified for a
  208. // particular subnet. If not, the global value should be present.
  209. // If there is no global value, exception is thrown.
  210. Triplet<uint32_t> valid = getParam("valid-lifetime");
  211. // Subnet ID is optional. If it is not supplied the value of 0 is used,
  212. // which means autogenerate.
  213. SubnetID subnet_id =
  214. static_cast<SubnetID>(uint32_values_->getOptionalParam("id", 0));
  215. stringstream s;
  216. s << addr << "/" << static_cast<int>(len) << " with params: ";
  217. // t1 and t2 are optional may be not specified.
  218. if (!t1.unspecified()) {
  219. s << "t1=" << t1 << ", ";
  220. }
  221. if (!t2.unspecified()) {
  222. s << "t2=" << t2 << ", ";
  223. }
  224. s <<"valid-lifetime=" << valid;
  225. LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(s.str());
  226. Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
  227. subnet_ = subnet4;
  228. // match-client-id
  229. isc::util::OptionalValue<bool> match_client_id;
  230. try {
  231. match_client_id = boolean_values_->getParam("match-client-id");
  232. } catch (...) {
  233. // Ignore because this parameter is optional and it may be specified
  234. // in the global scope.
  235. }
  236. // If the match-client-id wasn't specified as a subnet specific parameter
  237. // check if there is global value specified.
  238. if (!match_client_id.isSpecified()) {
  239. // If not specified, use false.
  240. match_client_id.specify(globalContext()->boolean_values_->
  241. getOptionalParam("match-client-id", true));
  242. }
  243. // Set the match-client-id value for the subnet.
  244. subnet4->setMatchClientId(match_client_id.get());
  245. // next-server
  246. try {
  247. string next_server = globalContext()->string_values_->getParam("next-server");
  248. if (!next_server.empty()) {
  249. subnet4->setSiaddr(IOAddress(next_server));
  250. }
  251. } catch (const DhcpConfigError&) {
  252. // Don't care. next_server is optional. We can live without it
  253. } catch (...) {
  254. isc_throw(DhcpConfigError, "invalid parameter next-server ("
  255. << globalContext()->string_values_->getPosition("next-server")
  256. << ")");
  257. }
  258. // Try subnet specific value if it's available
  259. try {
  260. string next_server = string_values_->getParam("next-server");
  261. if (!next_server.empty()) {
  262. subnet4->setSiaddr(IOAddress(next_server));
  263. }
  264. } catch (const DhcpConfigError&) {
  265. // Don't care. next_server is optional. We can live without it
  266. } catch (...) {
  267. isc_throw(DhcpConfigError, "invalid parameter next-server ("
  268. << string_values_->getPosition("next-server")
  269. << ")");
  270. }
  271. // Try setting up client class (if specified)
  272. try {
  273. string client_class = string_values_->getParam("client-class");
  274. subnet4->allowClientClass(client_class);
  275. } catch (const DhcpConfigError&) {
  276. // That's ok if it fails. client-class is optional.
  277. }
  278. }
  279. };
  280. /// @brief this class parses list of DHCP4 subnets
  281. ///
  282. /// This is a wrapper parser that handles the whole list of Subnet4
  283. /// definitions. It iterates over all entries and creates Subnet4ConfigParser
  284. /// for each entry.
  285. class Subnets4ListConfigParser : public DhcpConfigParser {
  286. public:
  287. /// @brief constructor
  288. ///
  289. /// @param dummy first argument, always ignored. All parsers accept a
  290. /// string parameter "name" as their first argument.
  291. Subnets4ListConfigParser(const std::string&) {
  292. }
  293. /// @brief parses contents of the list
  294. ///
  295. /// Iterates over all entries on the list and creates Subnet4ConfigParser
  296. /// for each entry.
  297. ///
  298. /// @param subnets_list pointer to a list of IPv4 subnets
  299. void build(ConstElementPtr subnets_list) {
  300. BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
  301. ParserPtr parser(new Subnet4ConfigParser("subnet"));
  302. parser->build(subnet);
  303. }
  304. }
  305. /// @brief commits subnets definitions.
  306. ///
  307. /// Does nothing.
  308. void commit() {
  309. }
  310. /// @brief Returns Subnet4ListConfigParser object
  311. /// @param param_name name of the parameter
  312. /// @return Subnets4ListConfigParser object
  313. static DhcpConfigParser* factory(const std::string& param_name) {
  314. return (new Subnets4ListConfigParser(param_name));
  315. }
  316. };
  317. } // anonymous namespace
  318. namespace isc {
  319. namespace dhcp {
  320. /// @brief creates global parsers
  321. ///
  322. /// This method creates global parsers that parse global parameters, i.e.
  323. /// those that take format of Dhcp4/param1, Dhcp4/param2 and so forth.
  324. ///
  325. /// @param config_id pointer to received global configuration entry
  326. /// @param element pointer to the element to be parsed
  327. /// @return parser for specified global DHCPv4 parameter
  328. /// @throw NotImplemented if trying to create a parser for unknown
  329. /// config element
  330. DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
  331. ConstElementPtr element) {
  332. DhcpConfigParser* parser = NULL;
  333. if ((config_id.compare("valid-lifetime") == 0) ||
  334. (config_id.compare("renew-timer") == 0) ||
  335. (config_id.compare("rebind-timer") == 0)) {
  336. parser = new Uint32Parser(config_id,
  337. globalContext()->uint32_values_);
  338. } else if (config_id.compare("interfaces-config") == 0) {
  339. parser = new IfacesConfigParser4();
  340. } else if (config_id.compare("subnet4") == 0) {
  341. parser = new Subnets4ListConfigParser(config_id);
  342. } else if (config_id.compare("option-data") == 0) {
  343. parser = new OptionDataListParser(config_id, CfgOptionPtr(), AF_INET);
  344. } else if (config_id.compare("option-def") == 0) {
  345. parser = new OptionDefListParser(config_id, globalContext());
  346. } else if ((config_id.compare("version") == 0) ||
  347. (config_id.compare("next-server") == 0)) {
  348. parser = new StringParser(config_id,
  349. globalContext()->string_values_);
  350. } else if (config_id.compare("lease-database") == 0) {
  351. parser = new DbAccessParser(config_id, *globalContext());
  352. } else if (config_id.compare("hooks-libraries") == 0) {
  353. parser = new HooksLibrariesParser(config_id);
  354. } else if (config_id.compare("echo-client-id") == 0) {
  355. parser = new BooleanParser(config_id, globalContext()->boolean_values_);
  356. } else if (config_id.compare("dhcp-ddns") == 0) {
  357. parser = new D2ClientConfigParser(config_id);
  358. } else if (config_id.compare("match-client-id") == 0) {
  359. parser = new BooleanParser(config_id, globalContext()->boolean_values_);
  360. } else if (config_id.compare("control-socket") == 0) {
  361. parser = new ControlSocketParser(config_id);
  362. } else {
  363. isc_throw(DhcpConfigError,
  364. "unsupported global configuration parameter: "
  365. << config_id << " (" << element->getPosition() << ")");
  366. }
  367. return (parser);
  368. }
  369. void commitGlobalOptions() {
  370. // Although the function is modest for now, it is certain that the number
  371. // of global switches will increase over time, hence the name.
  372. // Set whether v4 server is supposed to echo back client-id (yes = RFC6842
  373. // compatible, no = backward compatibility)
  374. try {
  375. bool echo_client_id = globalContext()->boolean_values_->getParam("echo-client-id");
  376. CfgMgr::instance().echoClientId(echo_client_id);
  377. } catch (...) {
  378. // Ignore errors. This flag is optional
  379. }
  380. }
  381. isc::data::ConstElementPtr
  382. configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
  383. if (!config_set) {
  384. ConstElementPtr answer = isc::config::createAnswer(1,
  385. string("Can't parse NULL config"));
  386. return (answer);
  387. }
  388. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND,
  389. DHCP4_CONFIG_START).arg(config_set->str());
  390. // Reset global context.
  391. globalContext().reset(new ParserContext(Option::V4));
  392. // Before starting any subnet operations, let's reset the subnet-id counter,
  393. // so newly recreated configuration starts with first subnet-id equal 1.
  394. Subnet::resetSubnetID();
  395. // Some of the values specified in the configuration depend on
  396. // other values. Typically, the values in the subnet4 structure
  397. // depend on the global values. Also, option values configuration
  398. // must be performed after the option definitions configurations.
  399. // Thus we group parsers and will fire them in the right order:
  400. // all parsers other than: lease-database, subnet4 and option-data parser,
  401. // then: option-data parser, subnet4 parser, lease-database parser.
  402. // Please do not change this order!
  403. ParserCollection independent_parsers;
  404. ParserPtr subnet_parser;
  405. ParserPtr option_parser;
  406. ParserPtr iface_parser;
  407. ParserPtr leases_parser;
  408. // Some of the parsers alter the state of the system in a way that can't
  409. // easily be undone. (Or alter it in a way such that undoing the change has
  410. // the same risk of failure as doing the change.)
  411. ParserPtr hooks_parser;
  412. // The subnet parsers implement data inheritance by directly
  413. // accessing global storage. For this reason the global data
  414. // parsers must store the parsed data into global storages
  415. // immediately. This may cause data inconsistency if the
  416. // parsing operation fails after the global storage has been
  417. // modified. We need to preserve the original global data here
  418. // so as we can rollback changes when an error occurs.
  419. ParserContext original_context(*globalContext());
  420. // Answer will hold the result.
  421. ConstElementPtr answer;
  422. // Rollback informs whether error occurred and original data
  423. // have to be restored to global storages.
  424. bool rollback = false;
  425. // config_pair holds the details of the current parser when iterating over
  426. // the parsers. It is declared outside the loops so in case of an error,
  427. // the name of the failing parser can be retrieved in the "catch" clause.
  428. ConfigPair config_pair;
  429. try {
  430. // Make parsers grouping.
  431. const std::map<std::string, ConstElementPtr>& values_map =
  432. config_set->mapValue();
  433. BOOST_FOREACH(config_pair, values_map) {
  434. ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
  435. config_pair.second));
  436. LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
  437. .arg(config_pair.first);
  438. if (config_pair.first == "subnet4") {
  439. subnet_parser = parser;
  440. } else if (config_pair.first == "lease-database") {
  441. leases_parser = parser;
  442. } else if (config_pair.first == "option-data") {
  443. option_parser = parser;
  444. } else if (config_pair.first == "interfaces-config") {
  445. // The interface parser is independent from any other
  446. // parser and can be run here before any other parsers.
  447. iface_parser = parser;
  448. parser->build(config_pair.second);
  449. } else if (config_pair.first == "hooks-libraries") {
  450. // Executing commit will alter currently-loaded hooks
  451. // libraries. Check if the supplied libraries are valid,
  452. // but defer the commit until everything else has committed.
  453. hooks_parser = parser;
  454. parser->build(config_pair.second);
  455. } else {
  456. // Those parsers should be started before other
  457. // parsers so we can call build straight away.
  458. independent_parsers.push_back(parser);
  459. parser->build(config_pair.second);
  460. // The commit operation here may modify the global storage
  461. // but we need it so as the subnet6 parser can access the
  462. // parsed data.
  463. parser->commit();
  464. }
  465. }
  466. // The option values parser is the next one to be run.
  467. std::map<std::string, ConstElementPtr>::const_iterator option_config =
  468. values_map.find("option-data");
  469. if (option_config != values_map.end()) {
  470. config_pair.first = "option-data";
  471. option_parser->build(option_config->second);
  472. option_parser->commit();
  473. }
  474. // The subnet parser is the next one to be run.
  475. std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
  476. values_map.find("subnet4");
  477. if (subnet_config != values_map.end()) {
  478. config_pair.first = "subnet4";
  479. subnet_parser->build(subnet_config->second);
  480. }
  481. // Get command socket configuration from the config file.
  482. // This code expects the following structure:
  483. // {
  484. // "socket-type": "unix",
  485. // "socket-name": "/tmp/kea4.sock"
  486. // }
  487. ConstElementPtr sock_cfg =
  488. CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
  489. // Close existing socket (if any).
  490. isc::config::CommandMgr::instance().closeCommandSocket();
  491. if (sock_cfg) {
  492. // This will create a control socket and will install external socket
  493. // in IfaceMgr. That socket will be monitored when Dhcp4Srv::receivePacket()
  494. // calls IfaceMgr::receive4() and callback in CommandMgr will be called,
  495. // if necessary. If there were previously open command socket, it will
  496. // be closed.
  497. isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
  498. }
  499. // the leases database parser is the last to be run.
  500. std::map<std::string, ConstElementPtr>::const_iterator leases_config =
  501. values_map.find("lease-database");
  502. if (leases_config != values_map.end()) {
  503. config_pair.first = "lease-database";
  504. leases_parser->build(leases_config->second);
  505. leases_parser->commit();
  506. }
  507. } catch (const isc::Exception& ex) {
  508. LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
  509. .arg(config_pair.first).arg(ex.what());
  510. answer = isc::config::createAnswer(1, ex.what());
  511. // An error occurred, so make sure that we restore original data.
  512. rollback = true;
  513. } catch (...) {
  514. // For things like bad_cast in boost::lexical_cast
  515. LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(config_pair.first);
  516. answer = isc::config::createAnswer(1, "undefined configuration"
  517. " processing error");
  518. // An error occurred, so make sure that we restore original data.
  519. rollback = true;
  520. }
  521. // So far so good, there was no parsing error so let's commit the
  522. // configuration. This will add created subnets and option values into
  523. // the server's configuration.
  524. // This operation should be exception safe but let's make sure.
  525. if (!rollback) {
  526. try {
  527. // No need to commit interface names as this is handled by the
  528. // CfgMgr::commit() function.
  529. // Apply global options
  530. commitGlobalOptions();
  531. // This occurs last as if it succeeds, there is no easy way
  532. // revert it. As a result, the failure to commit a subsequent
  533. // change causes problems when trying to roll back.
  534. if (hooks_parser) {
  535. hooks_parser->commit();
  536. }
  537. }
  538. catch (const isc::Exception& ex) {
  539. LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
  540. answer = isc::config::createAnswer(2, ex.what());
  541. rollback = true;
  542. } catch (...) {
  543. // For things like bad_cast in boost::lexical_cast
  544. LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
  545. answer = isc::config::createAnswer(2, "undefined configuration"
  546. " parsing error");
  547. rollback = true;
  548. }
  549. }
  550. // Rollback changes as the configuration parsing failed.
  551. if (rollback) {
  552. globalContext().reset(new ParserContext(original_context));
  553. return (answer);
  554. }
  555. LOG_INFO(dhcp4_logger, DHCP4_CONFIG_COMPLETE)
  556. .arg(CfgMgr::instance().getStagingCfg()->
  557. getConfigSummary(SrvConfig::CFGSEL_ALL4));
  558. // Everything was fine. Configuration is successful.
  559. answer = isc::config::createAnswer(0, "Configuration successful.");
  560. return (answer);
  561. }
  562. ParserContextPtr& globalContext() {
  563. static ParserContextPtr global_context_ptr(new ParserContext(Option::V4));
  564. return (global_context_ptr);
  565. }
  566. }; // end of isc::dhcp namespace
  567. }; // end of isc namespace