config_parser.cc 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. // Copyright (C) 2012 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 <stdint.h>
  15. #include <iostream>
  16. #include <vector>
  17. #include <map>
  18. #include <boost/foreach.hpp>
  19. #include <boost/shared_ptr.hpp>
  20. #include <boost/scoped_ptr.hpp>
  21. #include <boost/lexical_cast.hpp>
  22. #include <boost/algorithm/string.hpp>
  23. #include <util/encode/hex.h>
  24. #include <asiolink/io_address.h>
  25. #include <cc/data.h>
  26. #include <config/ccsession.h>
  27. #include <log/logger_support.h>
  28. #include <dhcp/triplet.h>
  29. #include <dhcp/pool.h>
  30. #include <dhcp/subnet.h>
  31. #include <dhcp/cfgmgr.h>
  32. #include <dhcp6/config_parser.h>
  33. #include <dhcp6/dhcp6_log.h>
  34. using namespace std;
  35. using namespace isc::data;
  36. using namespace isc::asiolink;
  37. namespace isc {
  38. namespace dhcp {
  39. /// @brief auxiliary type used for storing element name and its parser
  40. typedef pair<string, ConstElementPtr> ConfigPair;
  41. /// @brief a factory method that will create a parser for a given element name
  42. typedef DhcpConfigParser* ParserFactory(const std::string& config_id);
  43. /// @brief a collection of factories that creates parsers for specified element names
  44. typedef std::map<std::string, ParserFactory*> FactoryMap;
  45. /// @brief a collection of elements that store uint32 values (e.g. renew-timer = 900)
  46. typedef std::map<string, uint32_t> Uint32Storage;
  47. /// @brief a collection of elements that store string values
  48. typedef std::map<string, string> StringStorage;
  49. /// @brief a collection of pools
  50. ///
  51. /// That type is used as intermediate storage, when pools are parsed, but there is
  52. /// no subnet object created yet to store them.
  53. typedef std::vector<Pool6Ptr> PoolStorage;
  54. typedef std::vector<OptionPtr> OptionStorage;
  55. /// @brief Global uint32 parameters that will be used as defaults.
  56. Uint32Storage uint32_defaults;
  57. /// @brief global string parameters that will be used as defaults.
  58. StringStorage string_defaults;
  59. /// @brief a dummy configuration parser
  60. ///
  61. /// It is a debugging parser. It does not configure anything,
  62. /// will accept any configuration and will just print it out
  63. /// on commit. Useful for debugging existing configurations and
  64. /// adding new ones.
  65. class DebugParser : public DhcpConfigParser {
  66. public:
  67. /// @brief Constructor
  68. ///
  69. /// See \ref DhcpConfigParser class for details.
  70. ///
  71. /// @param param_name name of the parsed parameter
  72. DebugParser(const std::string& param_name)
  73. :param_name_(param_name) {
  74. }
  75. /// @brief builds parameter value
  76. ///
  77. /// See \ref DhcpConfigParser class for details.
  78. ///
  79. /// @param new_config pointer to the new configuration
  80. virtual void build(ConstElementPtr new_config) {
  81. std::cout << "Build for token: [" << param_name_ << "] = ["
  82. << value_->str() << "]" << std::endl;
  83. value_ = new_config;
  84. }
  85. /// @brief pretends to apply the configuration
  86. ///
  87. /// This is a method required by base class. It pretends to apply the
  88. /// configuration, but in fact it only prints the parameter out.
  89. ///
  90. /// See \ref DhcpConfigParser class for details.
  91. virtual void commit() {
  92. // Debug message. The whole DebugParser class is used only for parser
  93. // debugging, and is not used in production code. It is very convenient
  94. // to keep it around. Please do not turn this cout into logger calls.
  95. std::cout << "Commit for token: [" << param_name_ << "] = ["
  96. << value_->str() << "]" << std::endl;
  97. }
  98. /// @brief factory that constructs DebugParser objects
  99. ///
  100. /// @param param_name name of the parameter to be parsed
  101. static DhcpConfigParser* Factory(const std::string& param_name) {
  102. return (new DebugParser(param_name));
  103. }
  104. protected:
  105. /// name of the parsed parameter
  106. std::string param_name_;
  107. /// pointer to the actual value of the parameter
  108. ConstElementPtr value_;
  109. };
  110. /// @brief Configuration parser for uint32 parameters
  111. ///
  112. /// This class is a generic parser that is able to handle any uint32 integer
  113. /// type. By default it stores the value in external global container
  114. /// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
  115. /// in subnet config), it can be pointed to a different storage, using
  116. /// setStorage() method. This class follows the parser interface, laid out
  117. /// in its base class, \ref DhcpConfigParser.
  118. ///
  119. /// For overview of usability of this generic purpose parser, see
  120. /// \ref dhcpv6-config-inherit page.
  121. class Uint32Parser : public DhcpConfigParser {
  122. public:
  123. /// @brief constructor for Uint32Parser
  124. /// @param param_name name of the configuration parameter being parsed
  125. Uint32Parser(const std::string& param_name)
  126. :storage_(&uint32_defaults), param_name_(param_name) {
  127. }
  128. /// @brief builds parameter value
  129. ///
  130. /// Parses configuration entry and stores it in a storage. See
  131. /// \ref setStorage() for details.
  132. ///
  133. /// @param value pointer to the content of parsed values
  134. virtual void build(ConstElementPtr value) {
  135. bool parse_error = false;
  136. // Cast the provided value to int64 value to check.
  137. int64_t int64value = 0;
  138. try {
  139. // Parsing the value as a int64 value allows to
  140. // check if the provided value is within the range
  141. // of uint32_t (is not negative or greater than
  142. // maximal uint32_t value.
  143. int64value = boost::lexical_cast<int64_t>(value->str());
  144. } catch (const boost::bad_lexical_cast&) {
  145. parse_error = true;
  146. }
  147. if (!parse_error) {
  148. if ((int64value < 0) ||
  149. (int64value > std::numeric_limits<uint32_t>::max())) {
  150. parse_error = true;
  151. } else {
  152. try {
  153. value_ = boost::lexical_cast<uint32_t>(value->str());
  154. } catch (const boost::bad_lexical_cast &) {
  155. parse_error = true;
  156. }
  157. }
  158. }
  159. if (parse_error) {
  160. isc_throw(BadValue, "Failed to parse value " << value->str()
  161. << " as unsigned 32-bit integer.");
  162. }
  163. storage_->insert(pair<string, uint32_t>(param_name_, value_));
  164. }
  165. /// @brief does nothing
  166. ///
  167. /// This method is required for all parser. The value itself
  168. /// is not commited anywhere. Higher level parsers are expected to
  169. /// use values stored in the storage, e.g. renew-timer for a given
  170. /// subnet is stored in subnet-specific storage. It is not commited
  171. /// here, but is rather used by \ref Subnet6Parser when constructing
  172. /// the subnet.
  173. virtual void commit() {
  174. }
  175. /// @brief factory that constructs Uint32Parser objects
  176. ///
  177. /// @param param_name name of the parameter to be parsed
  178. static DhcpConfigParser* Factory(const std::string& param_name) {
  179. return (new Uint32Parser(param_name));
  180. }
  181. /// @brief sets storage for value of this parameter
  182. ///
  183. /// See \ref dhcpv6-config-inherit for details.
  184. ///
  185. /// @param storage pointer to the storage container
  186. void setStorage(Uint32Storage* storage) {
  187. storage_ = storage;
  188. }
  189. protected:
  190. /// pointer to the storage, where parsed value will be stored
  191. Uint32Storage* storage_;
  192. /// name of the parameter to be parsed
  193. std::string param_name_;
  194. /// the actual parsed value
  195. uint32_t value_;
  196. };
  197. /// @brief Configuration parser for string parameters
  198. ///
  199. /// This class is a generic parser that is able to handle any string
  200. /// parameter. By default it stores the value in external global container
  201. /// (string_defaults). If used in smaller scopes (e.g. to parse parameters
  202. /// in subnet config), it can be pointed to a different storage, using
  203. /// setStorage() method. This class follows the parser interface, laid out
  204. /// in its base class, \ref DhcpConfigParser.
  205. ///
  206. /// For overview of usability of this generic purpose parser, see
  207. /// \ref dhcpv6-config-inherit page.
  208. class StringParser : public DhcpConfigParser {
  209. public:
  210. /// @brief constructor for StringParser
  211. /// @param param_name name of the configuration parameter being parsed
  212. StringParser(const std::string& param_name)
  213. :storage_(&string_defaults), param_name_(param_name) {
  214. }
  215. /// @brief parses parameter value
  216. ///
  217. /// Parses configuration entry and stored it in storage. See
  218. /// \ref setStorage() for details.
  219. ///
  220. /// @param value pointer to the content of parsed values
  221. virtual void build(ConstElementPtr value) {
  222. value_ = value->str();
  223. boost::erase_all(value_, "\"");
  224. storage_->insert(pair<string, string>(param_name_, value_));
  225. }
  226. /// @brief does nothing
  227. ///
  228. /// This method is required for all parser. The value itself
  229. /// is not commited anywhere. Higher level parsers are expected to
  230. /// use values stored in the storage, e.g. renew-timer for a given
  231. /// subnet is stored in subnet-specific storage. It is not commited
  232. /// here, but is rather used by its parent parser when constructing
  233. /// an object, e.g. the subnet.
  234. virtual void commit() {
  235. }
  236. /// @brief factory that constructs StringParser objects
  237. ///
  238. /// @param param_name name of the parameter to be parsed
  239. static DhcpConfigParser* Factory(const std::string& param_name) {
  240. return (new StringParser(param_name));
  241. }
  242. /// @brief sets storage for value of this parameter
  243. ///
  244. /// See \ref dhcpv6-config-inherit for details.
  245. ///
  246. /// @param storage pointer to the storage container
  247. void setStorage(StringStorage* storage) {
  248. storage_ = storage;
  249. }
  250. protected:
  251. /// pointer to the storage, where parsed value will be stored
  252. StringStorage* storage_;
  253. /// name of the parameter to be parsed
  254. std::string param_name_;
  255. /// the actual parsed value
  256. std::string value_;
  257. };
  258. /// @brief parser for interface list definition
  259. ///
  260. /// This parser handles Dhcp6/interface entry.
  261. /// It contains a list of network interfaces that the server listens on.
  262. /// In particular, it can contain an entry called "all" or "any" that
  263. /// designates all interfaces.
  264. ///
  265. /// It is useful for parsing Dhcp6/interface parameter.
  266. class InterfaceListConfigParser : public DhcpConfigParser {
  267. public:
  268. /// @brief constructor
  269. ///
  270. /// As this is a dedicated parser, it must be used to parse
  271. /// "interface" parameter only. All other types will throw exception.
  272. ///
  273. /// @param param_name name of the configuration parameter being parsed
  274. InterfaceListConfigParser(const std::string& param_name) {
  275. if (param_name != "interface") {
  276. isc_throw(NotImplemented, "Internal error. Interface configuration "
  277. "parser called for the wrong parameter: " << param_name);
  278. }
  279. }
  280. /// @brief parses parameters value
  281. ///
  282. /// Parses configuration entry (list of parameters) and stores it in
  283. /// storage. See \ref setStorage() for details.
  284. ///
  285. /// @param value pointer to the content of parsed values
  286. virtual void build(ConstElementPtr value) {
  287. BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
  288. interfaces_.push_back(iface->str());
  289. }
  290. }
  291. /// @brief commits interfaces list configuration
  292. virtual void commit() {
  293. /// @todo: Implement per interface listening. Currently always listening
  294. /// on all interfaces.
  295. }
  296. /// @brief factory that constructs InterfaceListConfigParser objects
  297. ///
  298. /// @param param_name name of the parameter to be parsed
  299. static DhcpConfigParser* Factory(const std::string& param_name) {
  300. return (new InterfaceListConfigParser(param_name));
  301. }
  302. protected:
  303. /// contains list of network interfaces
  304. vector<string> interfaces_;
  305. };
  306. /// @brief parser for pool definition
  307. ///
  308. /// This parser handles pool definitions, i.e. a list of entries of one
  309. /// of two syntaxes: min-max and prefix/len. Pool6 objects are created
  310. /// and stored in chosen PoolStorage container.
  311. ///
  312. /// As there are no default values for pool, setStorage() must be called
  313. /// before build(). Otherwise exception will be thrown.
  314. ///
  315. /// It is useful for parsing Dhcp6/subnet6[X]/pool parameters.
  316. class PoolParser : public DhcpConfigParser {
  317. public:
  318. /// @brief constructor.
  319. PoolParser(const std::string& /*param_name*/)
  320. :pools_(NULL) {
  321. // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
  322. }
  323. /// @brief parses the actual list
  324. ///
  325. /// This method parses the actual list of interfaces.
  326. /// No validation is done at this stage, everything is interpreted as
  327. /// interface name.
  328. void build(ConstElementPtr pools_list) {
  329. // setStorage() should have been called before build
  330. if (!pools_) {
  331. isc_throw(NotImplemented, "Parser logic error. No pool storage set,"
  332. " but pool parser asked to parse pools");
  333. }
  334. BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
  335. // That should be a single pool representation. It should contain
  336. // text is form prefix/len or first - last. Note that spaces
  337. // are allowed
  338. string txt = text_pool->stringValue();
  339. // first let's remove any whitespaces
  340. boost::erase_all(txt, " "); // space
  341. boost::erase_all(txt, "\t"); // tabulation
  342. // Is this prefix/len notation?
  343. size_t pos = txt.find("/");
  344. if (pos != string::npos) {
  345. IOAddress addr("::");
  346. uint8_t len = 0;
  347. try {
  348. addr = IOAddress(txt.substr(0, pos));
  349. // start with the first character after /
  350. string prefix_len = txt.substr(pos + 1);
  351. // It is lexical cast to int and then downcast to uint8_t.
  352. // Direct cast to uint8_t (which is really an unsigned char)
  353. // will result in interpreting the first digit as output
  354. // value and throwing exception if length is written on two
  355. // digits (because there are extra characters left over).
  356. // No checks for values over 128. Range correctness will
  357. // be checked in Pool6 constructor.
  358. len = boost::lexical_cast<int>(prefix_len);
  359. } catch (...) {
  360. isc_throw(Dhcp6ConfigError, "Failed to parse pool "
  361. "definition: " << text_pool->stringValue());
  362. }
  363. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, addr, len));
  364. pools_->push_back(pool);
  365. continue;
  366. }
  367. // Is this min-max notation?
  368. pos = txt.find("-");
  369. if (pos != string::npos) {
  370. // using min-max notation
  371. IOAddress min(txt.substr(0,pos - 1));
  372. IOAddress max(txt.substr(pos + 1));
  373. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
  374. pools_->push_back(pool);
  375. continue;
  376. }
  377. isc_throw(Dhcp6ConfigError, "Failed to parse pool definition:"
  378. << text_pool->stringValue() <<
  379. ". Does not contain - (for min-max) nor / (prefix/len)");
  380. }
  381. }
  382. /// @brief sets storage for value of this parameter
  383. ///
  384. /// See \ref dhcpv6-config-inherit for details.
  385. ///
  386. /// @param storage pointer to the storage container
  387. void setStorage(PoolStorage* storage) {
  388. pools_ = storage;
  389. }
  390. /// @brief does nothing.
  391. ///
  392. /// This method is required for all parser. The value itself
  393. /// is not commited anywhere. Higher level parsers (for subnet) are expected
  394. /// to use values stored in the storage.
  395. virtual void commit() {}
  396. /// @brief factory that constructs PoolParser objects
  397. ///
  398. /// @param param_name name of the parameter to be parsed
  399. static DhcpConfigParser* Factory(const std::string& param_name) {
  400. return (new PoolParser(param_name));
  401. }
  402. protected:
  403. /// @brief pointer to the actual Pools storage
  404. ///
  405. /// That is typically a storage somewhere in Subnet parser
  406. /// (an upper level parser).
  407. PoolStorage* pools_;
  408. };
  409. /// @brief Parser for option data value.
  410. ///
  411. /// This parser parses configuration entries that specify value of
  412. /// a single option. These entries include option name, option code
  413. /// and data carried by the option. If parsing is successful than
  414. /// instance of an option is created and added to the storage provided
  415. /// by the calling class.
  416. class OptionDataParser : public DhcpConfigParser {
  417. public:
  418. /// @brief Constructor.
  419. ///
  420. /// Class constructor.
  421. OptionDataParser(const std::string&) { }
  422. /// @brief Parses the single option data.
  423. ///
  424. /// This method parses the data of a single option from the configuration.
  425. /// The option data includes option name, option code and data being
  426. /// carried by this option. Eventually it creates the instance of the
  427. /// option.
  428. ///
  429. /// @param option_data_entries collection of entries that define value
  430. /// for a particular option.
  431. /// @throw isc::InvalidParameter if invalid parameter specified in
  432. /// the configuration.
  433. virtual void build(ConstElementPtr option_data_entries) {
  434. BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
  435. ParserPtr parser;
  436. if (param.first == "name") {
  437. boost::shared_ptr<StringParser>
  438. name_parser(dynamic_cast<StringParser*>(StringParser::Factory(param.first)));
  439. if (name_parser) {
  440. name_parser->setStorage(&string_values_);
  441. parser = name_parser;
  442. }
  443. } else if (param.first == "code") {
  444. boost::shared_ptr<Uint32Parser>
  445. code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::Factory(param.first)));
  446. if (code_parser) {
  447. code_parser->setStorage(&uint32_values_);
  448. parser = code_parser;
  449. }
  450. } else if (param.first == "data") {
  451. boost::shared_ptr<StringParser>
  452. value_parser(dynamic_cast<StringParser*>(StringParser::Factory(param.first)));
  453. if (value_parser) {
  454. value_parser->setStorage(&string_values_);
  455. parser = value_parser;
  456. }
  457. } else {
  458. isc_throw(Dhcp6ConfigError,
  459. "Parser error: option-data parameter not supported: "
  460. << param.first);
  461. }
  462. parser->build(param.second);
  463. }
  464. // Try to create the option instance.
  465. createOption();
  466. }
  467. /// @brief Does nothing.
  468. ///
  469. /// This function does noting because option data is committed
  470. /// by a higher level parser.
  471. virtual void commit() { }
  472. /// @brief Set storage for the parser.
  473. ///
  474. /// Sets storage for the parser. This storage points to the
  475. /// vector of options and is used by multiple instances of
  476. /// OptionDataParser. Each instance creates exactly one object
  477. /// of dhcp::Option or derived type and appends it to this
  478. /// storage.
  479. ///
  480. /// @param storage pointer to the options storage
  481. void setStorage(OptionStorage* storage) {
  482. options_ = storage;
  483. }
  484. private:
  485. /// @brief Create option instance.
  486. ///
  487. /// Creates an instance of an option and adds it to the provided
  488. /// options storage. If the option data parsed by \ref build function
  489. /// are invalid or insufficient it emits exception.
  490. ///
  491. /// @throw Dhcp6ConfigError if parameters provided in the configuration
  492. /// are invalid.
  493. void createOption() {
  494. // Option code is held in the uint32_t storage but is supposed to
  495. // be uint16_t value. We need to check that value in the configuration
  496. // does not exceed range of uint16_t and is not zero.
  497. uint32_t option_code = getUint32Param("code");
  498. if (option_code == 0) {
  499. isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
  500. << " be equal to zero. Option code '0' is reserved in"
  501. << " DHCPv6.");
  502. } else if (option_code > std::numeric_limits<uint16_t>::max()) {
  503. isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
  504. << " exceed " << std::numeric_limits<uint16_t>::max());
  505. }
  506. // Check the option name has been specified, is non-empty and does not
  507. // contain spaces.
  508. // @todo possibly some more restrictions apply here?
  509. std::string option_name = getStringParam("name");
  510. if (option_name.empty()) {
  511. isc_throw(Dhcp6ConfigError, "Parser error: option name must not be"
  512. << " empty");
  513. } else if (option_name.find(" ") != std::string::npos) {
  514. isc_throw(Dhcp6ConfigError, "Parser error: option name must not contain"
  515. << " spaces");
  516. }
  517. std::string option_data = getStringParam("data");
  518. std::vector<uint8_t> binary;
  519. try {
  520. util::encode::decodeHex(option_data, binary);
  521. } catch (...) {
  522. isc_throw(Dhcp6ConfigError, "Parser error: option data is not a valid"
  523. << " string of hexadecimal digits: " << option_data);
  524. }
  525. // Create the actual option.
  526. // @todo Currently we simply create dhcp::Option instance here but we will
  527. // need to use dedicated factory functions once the option definitions are
  528. // created for all options.
  529. OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
  530. binary));
  531. // If option is created succesfully, add it to the storage.
  532. options_->push_back(option);
  533. }
  534. /// @brief Get a parameter from the strings storage.
  535. ///
  536. /// @param param_id parameter identifier.
  537. /// @throw Dhcp6ConfigError if parameter has not been found.
  538. std::string getStringParam(const std::string& param_id) const {
  539. StringStorage::const_iterator param = string_values_.find(param_id);
  540. if (param == string_values_.end()) {
  541. isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
  542. << " '" << param_id << "' not specified");
  543. }
  544. return (param->second);
  545. }
  546. /// @brief Get a parameter from the uint32 values storage.
  547. ///
  548. /// @param param_id parameter identifier.
  549. /// @throw Dhcp6ConfigError if parameter has not been found.
  550. uint32_t getUint32Param(const std::string& param_id) const {
  551. Uint32Storage::const_iterator param = uint32_values_.find(param_id);
  552. if (param == uint32_values_.end()) {
  553. isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
  554. << " '" << param_id << "' not specified");
  555. }
  556. return (param->second);
  557. }
  558. /// Storage for uint32 values (e.g. option code).
  559. Uint32Storage uint32_values_;
  560. /// Storage for string values (e.g. option name or data).
  561. StringStorage string_values_;
  562. /// Pointer to options storage. This storage is provided by
  563. /// the calling class and is shared by all OptionDataParser objects.
  564. OptionStorage* options_;
  565. };
  566. /// @brief Parser for option data values with ina subnet.
  567. ///
  568. /// This parser iterates over all entries that define options
  569. /// data for a particular subnet and creates a collection of options.
  570. /// If parsing is successful, all these options are added to the Subnet
  571. /// object.
  572. class OptionDataListParser : public DhcpConfigParser {
  573. public:
  574. /// @brief Constructor.
  575. OptionDataListParser(const std::string&) { }
  576. /// @brief Parses entries that define options' data for a subnet.
  577. ///
  578. /// This method iterates over all entries that define option data
  579. /// for options within a single subnet and creates options' instances.
  580. ///
  581. /// @param option_data_list pointer to a list of options' data sets.
  582. /// @throw Dhcp6ConfigError if option parsing failed.
  583. void build(ConstElementPtr option_data_list) {
  584. BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
  585. boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
  586. // options_ member will hold instances of all options thus
  587. // each OptionDataParser takes it as a storage.
  588. parser->setStorage(options_);
  589. // Build the instance of a singkle option.
  590. parser->build(option_value);
  591. }
  592. }
  593. /// @brief Set storage for option instances.
  594. ///
  595. /// @param storage pointer to options storage.
  596. void setStorage(OptionStorage* storage) {
  597. options_ = storage;
  598. }
  599. /// @brief Does nothing.
  600. ///
  601. /// @todo Currently this function does nothing but in the future
  602. /// we may need to extend it to commit at this level.
  603. void commit() { }
  604. /// @brief Create DhcpDataListParser object
  605. ///
  606. /// @param param_name param name.
  607. ///
  608. /// @return DhcpConfigParser object.
  609. static DhcpConfigParser* Factory(const std::string& param_name) {
  610. return (new OptionDataListParser(param_name));
  611. }
  612. /// Pointer to options instances storage.
  613. OptionStorage* options_;
  614. };
  615. /// @brief this class parses a single subnet
  616. ///
  617. /// This class parses the whole subnet definition. It creates parsers
  618. /// for received configuration parameters as needed.
  619. class Subnet6ConfigParser : public DhcpConfigParser {
  620. public:
  621. /// @brief constructor
  622. Subnet6ConfigParser(const std::string& ) {
  623. // The parameter should always be "subnet", but we don't check here
  624. // against it in case some wants to reuse this parser somewhere.
  625. }
  626. /// @brief parses parameter value
  627. ///
  628. /// @param subnet pointer to the content of subnet definition
  629. void build(ConstElementPtr subnet) {
  630. BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
  631. ParserPtr parser(createSubnet6ConfigParser(param.first));
  632. // if this is an Uint32 parser, tell it to store the values
  633. // in values_, rather than in global storage
  634. boost::shared_ptr<Uint32Parser> uintParser =
  635. boost::dynamic_pointer_cast<Uint32Parser>(parser);
  636. if (uintParser) {
  637. uintParser->setStorage(&uint32_values_);
  638. } else {
  639. boost::shared_ptr<StringParser> stringParser =
  640. boost::dynamic_pointer_cast<StringParser>(parser);
  641. if (stringParser) {
  642. stringParser->setStorage(&string_values_);
  643. } else {
  644. boost::shared_ptr<PoolParser> poolParser =
  645. boost::dynamic_pointer_cast<PoolParser>(parser);
  646. if (poolParser) {
  647. poolParser->setStorage(&pools_);
  648. } else {
  649. boost::shared_ptr<OptionDataListParser> option_data_list_parser =
  650. boost::dynamic_pointer_cast<OptionDataListParser>(parser);
  651. option_data_list_parser->setStorage(&options_);
  652. }
  653. }
  654. }
  655. parser->build(param.second);
  656. parsers_.push_back(parser);
  657. }
  658. // Ok, we now have subnet parsed
  659. }
  660. /// @brief commits received configuration.
  661. ///
  662. /// This method does most of the configuration. Many other parsers are just
  663. /// storing the values that are actually consumed here. Pool definitions
  664. /// created in other parsers are used here and added to newly created Subnet6
  665. /// objects. Subnet6 are then added to DHCP CfgMgr.
  666. void commit() {
  667. StringStorage::const_iterator it = string_values_.find("subnet");
  668. if (it == string_values_.end()) {
  669. isc_throw(Dhcp6ConfigError,
  670. "Mandatory subnet definition in subnet missing");
  671. }
  672. string subnet_txt = it->second;
  673. boost::erase_all(subnet_txt, " ");
  674. boost::erase_all(subnet_txt, "\t");
  675. size_t pos = subnet_txt.find("/");
  676. if (pos == string::npos) {
  677. isc_throw(Dhcp6ConfigError,
  678. "Invalid subnet syntax (prefix/len expected):" << it->second);
  679. }
  680. IOAddress addr(subnet_txt.substr(0, pos));
  681. uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
  682. Triplet<uint32_t> t1 = getParam("renew-timer");
  683. Triplet<uint32_t> t2 = getParam("rebind-timer");
  684. Triplet<uint32_t> pref = getParam("preferred-lifetime");
  685. Triplet<uint32_t> valid = getParam("valid-lifetime");
  686. /// @todo: Convert this to logger once the parser is working reliably
  687. stringstream tmp;
  688. tmp << addr.toText() << "/" << (int)len
  689. << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
  690. << pref << ", valid=" << valid;
  691. LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(tmp.str());
  692. Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
  693. for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
  694. subnet->addPool6(*it);
  695. }
  696. BOOST_FOREACH(OptionPtr option, options_) {
  697. subnet->addOption(option);
  698. }
  699. CfgMgr::instance().addSubnet6(subnet);
  700. }
  701. protected:
  702. /// @brief creates parsers for entries in subnet definition
  703. ///
  704. /// @todo Add subnet-specific things here (e.g. subnet-specific options)
  705. ///
  706. /// @param config_id name od the entry
  707. /// @return parser object for specified entry name
  708. DhcpConfigParser* createSubnet6ConfigParser(const std::string& config_id) {
  709. FactoryMap factories;
  710. factories.insert(pair<string, ParserFactory*>(
  711. "preferred-lifetime", Uint32Parser::Factory));
  712. factories.insert(pair<string, ParserFactory*>(
  713. "valid-lifetime", Uint32Parser::Factory));
  714. factories.insert(pair<string, ParserFactory*>(
  715. "renew-timer", Uint32Parser::Factory));
  716. factories.insert(pair<string, ParserFactory*>(
  717. "rebind-timer", Uint32Parser::Factory));
  718. factories.insert(pair<string, ParserFactory*>(
  719. "subnet", StringParser::Factory));
  720. factories.insert(pair<string, ParserFactory*>(
  721. "pool", PoolParser::Factory));
  722. factories.insert(pair<string, ParserFactory*>(
  723. "option-data", OptionDataListParser::Factory));
  724. FactoryMap::iterator f = factories.find(config_id);
  725. if (f == factories.end()) {
  726. // Used for debugging only.
  727. // return new DebugParser(config_id);
  728. isc_throw(NotImplemented,
  729. "Parser error: Subnet6 parameter not supported: "
  730. << config_id);
  731. }
  732. return (f->second(config_id));
  733. }
  734. /// @brief returns value for a given parameter (after using inheritance)
  735. ///
  736. /// This method implements inheritance. For a given parameter name, it first
  737. /// checks if there is a global value for it and overwrites it with specific
  738. /// value if such value was defined in subnet.
  739. ///
  740. /// @param name name of the parameter
  741. /// @return triplet with the parameter name
  742. Triplet<uint32_t> getParam(const std::string& name) {
  743. uint32_t value = 0;
  744. bool found = false;
  745. Uint32Storage::iterator global = uint32_defaults.find(name);
  746. if (global != uint32_defaults.end()) {
  747. value = global->second;
  748. found = true;
  749. }
  750. Uint32Storage::iterator local = uint32_values_.find(name);
  751. if (local != uint32_values_.end()) {
  752. value = local->second;
  753. found = true;
  754. }
  755. if (found) {
  756. return (Triplet<uint32_t>(value));
  757. } else {
  758. isc_throw(Dhcp6ConfigError, "Mandatory parameter " << name
  759. << " missing (no global default and no subnet-"
  760. << "specific value)");
  761. }
  762. }
  763. /// storage for subnet-specific uint32 values
  764. Uint32Storage uint32_values_;
  765. /// storage for subnet-specific integer values
  766. StringStorage string_values_;
  767. /// storage for pools belonging to this subnet
  768. PoolStorage pools_;
  769. /// storage for options belonging to this subnet
  770. OptionStorage options_;
  771. /// parsers are stored here
  772. ParserCollection parsers_;
  773. };
  774. /// @brief this class parses list of subnets
  775. ///
  776. /// This is a wrapper parser that handles the whole list of Subnet6
  777. /// definitions. It iterates over all entries and creates Subnet6ConfigParser
  778. /// for each entry.
  779. class Subnets6ListConfigParser : public DhcpConfigParser {
  780. public:
  781. /// @brief constructor
  782. ///
  783. Subnets6ListConfigParser(const std::string&) {
  784. /// parameter name is ignored
  785. }
  786. /// @brief parses contents of the list
  787. ///
  788. /// Iterates over all entries on the list and creates Subnet6ConfigParser
  789. /// for each entry.
  790. ///
  791. /// @param subnets_list pointer to a list of IPv6 subnets
  792. void build(ConstElementPtr subnets_list) {
  793. // No need to define FactoryMap here. There's only one type
  794. // used: Subnet6ConfigParser
  795. BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
  796. ParserPtr parser(new Subnet6ConfigParser("subnet"));
  797. parser->build(subnet);
  798. subnets_.push_back(parser);
  799. }
  800. }
  801. /// @brief commits subnets definitions.
  802. ///
  803. /// Iterates over all Subnet6 parsers. Each parser contains definitions
  804. /// of a single subnet and its parameters and commits each subnet separately.
  805. void commit() {
  806. // @todo: Implement more subtle reconfiguration than toss
  807. // the old one and replace with the new one.
  808. // remove old subnets
  809. CfgMgr::instance().deleteSubnets6();
  810. BOOST_FOREACH(ParserPtr subnet, subnets_) {
  811. subnet->commit();
  812. }
  813. }
  814. /// @brief Returns Subnet6ListConfigParser object
  815. /// @param param_name name of the parameter
  816. /// @return Subnets6ListConfigParser object
  817. static DhcpConfigParser* Factory(const std::string& param_name) {
  818. return (new Subnets6ListConfigParser(param_name));
  819. }
  820. /// @brief collection of subnet parsers.
  821. ParserCollection subnets_;
  822. };
  823. /// @brief creates global parsers
  824. ///
  825. /// This method creates global parsers that parse global parameters, i.e.
  826. /// those that take format of Dhcp6/param1, Dhcp6/param2 and so forth.
  827. ///
  828. /// @param config_id pointer to received global configuration entry
  829. /// @return parser for specified global DHCPv6 parameter
  830. DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
  831. FactoryMap factories;
  832. factories.insert(pair<string, ParserFactory*>(
  833. "preferred-lifetime", Uint32Parser::Factory));
  834. factories.insert(pair<string, ParserFactory*>(
  835. "valid-lifetime", Uint32Parser::Factory));
  836. factories.insert(pair<string, ParserFactory*>(
  837. "renew-timer", Uint32Parser::Factory));
  838. factories.insert(pair<string, ParserFactory*>(
  839. "rebind-timer", Uint32Parser::Factory));
  840. factories.insert(pair<string, ParserFactory*>(
  841. "interface", InterfaceListConfigParser::Factory));
  842. factories.insert(pair<string, ParserFactory*>(
  843. "subnet6", Subnets6ListConfigParser::Factory));
  844. factories.insert(pair<string, ParserFactory*>(
  845. "version", StringParser::Factory));
  846. FactoryMap::iterator f = factories.find(config_id);
  847. if (f == factories.end()) {
  848. // Used for debugging only.
  849. // return new DebugParser(config_id);
  850. isc_throw(NotImplemented,
  851. "Parser error: Global configuration parameter not supported: "
  852. << config_id);
  853. }
  854. return (f->second(config_id));
  855. }
  856. /// @brief configures DHCPv6 server
  857. ///
  858. /// This function is called every time a new configuration is received. The extra
  859. /// parameter is a reference to DHCPv6 server component. It is currently not used
  860. /// and CfgMgr::instance() is accessed instead.
  861. ///
  862. /// This method does not throw. It catches all exceptions and returns them as
  863. /// reconfiguration statuses. It may return the following response codes:
  864. /// 0 - configuration successful
  865. /// 1 - malformed configuration (parsing failed)
  866. /// 2 - logical error (parsing was successful, but the values are invalid)
  867. ///
  868. /// @param config_set a new configuration for DHCPv6 server
  869. /// @return answer that contains result of reconfiguration
  870. ConstElementPtr
  871. configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) {
  872. if (!config_set) {
  873. isc_throw(Dhcp6ConfigError,
  874. "Null pointer is passed to configuration parser");
  875. }
  876. /// @todo: append most essential info here (like "2 new subnets configured")
  877. string config_details;
  878. LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_START).arg(config_set->str());
  879. ParserCollection parsers;
  880. try {
  881. BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
  882. ParserPtr parser(createGlobalDhcpConfigParser(config_pair.first));
  883. parser->build(config_pair.second);
  884. parsers.push_back(parser);
  885. }
  886. } catch (const isc::Exception& ex) {
  887. ConstElementPtr answer = isc::config::createAnswer(1,
  888. string("Configuration parsing failed:") + ex.what());
  889. return (answer);
  890. } catch (...) {
  891. // for things like bad_cast in boost::lexical_cast
  892. ConstElementPtr answer = isc::config::createAnswer(1,
  893. string("Configuration parsing failed"));
  894. }
  895. try {
  896. BOOST_FOREACH(ParserPtr parser, parsers) {
  897. parser->commit();
  898. }
  899. }
  900. catch (const isc::Exception& ex) {
  901. ConstElementPtr answer = isc::config::createAnswer(2,
  902. string("Configuration commit failed:") + ex.what());
  903. return (answer);
  904. } catch (...) {
  905. // for things like bad_cast in boost::lexical_cast
  906. ConstElementPtr answer = isc::config::createAnswer(2,
  907. string("Configuration commit failed"));
  908. }
  909. LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);
  910. ConstElementPtr answer = isc::config::createAnswer(0, "Configuration commited.");
  911. return (answer);
  912. }
  913. }; // end of isc::dhcp namespace
  914. }; // end of isc namespace