cfgmgr.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. // Copyright (C) 2012-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. #ifndef CFGMGR_H
  15. #define CFGMGR_H
  16. #include <asiolink/io_address.h>
  17. #include <dhcp/option.h>
  18. #include <dhcp/option_space.h>
  19. #include <dhcp/classify.h>
  20. #include <dhcpsrv/d2_client_mgr.h>
  21. #include <dhcpsrv/pool.h>
  22. #include <dhcpsrv/subnet.h>
  23. #include <dhcpsrv/srv_config.h>
  24. #include <util/buffer.h>
  25. #include <boost/shared_ptr.hpp>
  26. #include <boost/noncopyable.hpp>
  27. #include <map>
  28. #include <string>
  29. #include <vector>
  30. #include <list>
  31. namespace isc {
  32. namespace dhcp {
  33. /// @brief Exception thrown when the same interface has been specified twice.
  34. ///
  35. /// In particular, this exception is thrown when adding interface to the set
  36. /// of interfaces on which server is supposed to listen.
  37. class DuplicateListeningIface : public Exception {
  38. public:
  39. DuplicateListeningIface(const char* file, size_t line, const char* what) :
  40. isc::Exception(file, line, what) { };
  41. };
  42. /// @brief Exception thrown upon attempt to add subnet with an ID that belongs
  43. /// to the subnet that already exists.
  44. class DuplicateSubnetID : public Exception {
  45. public:
  46. DuplicateSubnetID(const char* file, size_t line, const char* what) :
  47. isc::Exception(file, line, what) { };
  48. };
  49. /// @brief Configuration Manager
  50. ///
  51. /// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
  52. /// servers. It currently holds information about zero or more subnets6.
  53. /// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
  54. /// basic "chunk" of configuration. It contains a range of assignable
  55. /// addresses.
  56. ///
  57. /// Below is a sketch of configuration inheritance (not implemented yet).
  58. /// Let's investigate the following configuration:
  59. ///
  60. /// @code
  61. /// preferred-lifetime 500;
  62. /// valid-lifetime 1000;
  63. /// subnet6 2001:db8:1::/48 {
  64. /// pool6 2001::db8:1::1 - 2001::db8:1::ff;
  65. /// };
  66. /// subnet6 2001:db8:2::/48 {
  67. /// valid-lifetime 2000;
  68. /// pool6 2001::db8:2::1 - 2001::db8:2::ff;
  69. /// };
  70. /// @endcode
  71. ///
  72. /// Parameters defined in a global scope are applicable to everything until
  73. /// they are overwritten in a smaller scope, in this case subnet6.
  74. /// In the example above, the first subnet6 has preferred lifetime of 500s
  75. /// and a valid lifetime of 1000s. The second subnet has preferred lifetime
  76. /// of 500s, but valid lifetime of 2000s.
  77. ///
  78. /// Parameter inheritance is likely to be implemented in configuration handling
  79. /// routines, so there is no storage capability in a global scope for
  80. /// subnet-specific parameters.
  81. ///
  82. /// @todo: Implement Subnet4 support (ticket #2237)
  83. /// @todo: Implement option definition support
  84. /// @todo: Implement parameter inheritance
  85. class CfgMgr : public boost::noncopyable {
  86. public:
  87. /// @brief A number of configurations held by @c CfgMgr.
  88. ///
  89. /// @todo Make it configurable.
  90. static const size_t CONFIG_LIST_SIZE;
  91. /// @brief returns a single instance of Configuration Manager
  92. ///
  93. /// CfgMgr is a singleton and this method is the only way of
  94. /// accessing it.
  95. static CfgMgr& instance();
  96. /// @brief Adds new DHCPv4 option space to the collection.
  97. ///
  98. /// @param space option space to be added.
  99. ///
  100. /// @throw isc::dhcp::InvalidOptionSpace invalid option space
  101. /// has been specified.
  102. void addOptionSpace4(const OptionSpacePtr& space);
  103. /// @brief Adds new DHCPv6 option space to the collection.
  104. ///
  105. /// @param space option space to be added.
  106. ///
  107. /// @throw isc::dhcp::InvalidOptionSpace invalid option space
  108. /// has been specified.
  109. void addOptionSpace6(const OptionSpacePtr& space);
  110. /// @brief Return option spaces for DHCPv4.
  111. ///
  112. /// @return A collection of option spaces.
  113. const OptionSpaceCollection& getOptionSpaces4() const {
  114. return (spaces4_);
  115. }
  116. /// @brief Return option spaces for DHCPv6.
  117. ///
  118. /// @return A collection of option spaces.
  119. const OptionSpaceCollection& getOptionSpaces6() const {
  120. return (spaces6_);
  121. }
  122. /// @brief get IPv6 subnet by address
  123. ///
  124. /// Finds a matching subnet, based on an address. This can be used
  125. /// in two cases: when trying to find an appropriate lease based on
  126. /// a) relay link address (that must be the address that is on link)
  127. /// b) our global address on the interface the message was received on
  128. /// (for directly connected clients)
  129. ///
  130. /// If there are any classes specified in a subnet, that subnet
  131. /// will be selected only if the client belongs to appropriate class.
  132. ///
  133. /// @note The client classification is checked before any relay
  134. /// information checks are conducted.
  135. ///
  136. /// If relay is true then relay info overrides (i.e. value the sysadmin
  137. /// can configure in Dhcp6/subnet6[X]/relay/ip-address) can be used.
  138. /// That is applicable only for relays. Those overrides must not be used
  139. /// for client address or for client hints. They are for link-addr field
  140. /// in the RELAY_FORW message only.
  141. ///
  142. /// @param hint an address that belongs to a searched subnet
  143. /// @param classes classes the client belongs to
  144. /// @param relay true if address specified in hint is a relay
  145. ///
  146. /// @return a subnet object (or NULL if no suitable match was fount)
  147. Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint,
  148. const isc::dhcp::ClientClasses& classes,
  149. const bool relay = false);
  150. /// @brief get IPv6 subnet by interface name
  151. ///
  152. /// Finds a matching local subnet, based on interface name. This
  153. /// is used for selecting subnets that were explicitly marked by the
  154. /// user as reachable over specified network interface.
  155. ///
  156. /// If there are any classes specified in a subnet, that subnet
  157. /// will be selected only if the client belongs to appropriate class.
  158. ///
  159. /// @param iface_name interface name
  160. /// @param classes classes the client belongs to
  161. ///
  162. /// @return a subnet object (or NULL if no suitable match was fount)
  163. Subnet6Ptr getSubnet6(const std::string& iface_name,
  164. const isc::dhcp::ClientClasses& classes);
  165. /// @brief get IPv6 subnet by interface-id
  166. ///
  167. /// Another possibility to find a subnet is based on interface-id.
  168. ///
  169. /// If there are any classes specified in a subnet, that subnet
  170. /// will be selected only if the client belongs to appropriate class.
  171. ///
  172. /// @param interface_id content of interface-id option returned by a relay
  173. /// @param classes classes the client belongs to
  174. ///
  175. /// @return a subnet object
  176. Subnet6Ptr getSubnet6(OptionPtr interface_id,
  177. const isc::dhcp::ClientClasses& classes);
  178. /// @brief adds an IPv6 subnet
  179. ///
  180. /// @param subnet new subnet to be added.
  181. void addSubnet6(const Subnet6Ptr& subnet);
  182. /// @todo: Add subnet6 removal routines. Currently it is not possible
  183. /// to remove subnets. The only case where subnet6 removal would be
  184. /// needed is a dynamic server reconfiguration - a use case that is not
  185. /// planned to be supported any time soon.
  186. /// @brief removes all IPv6 subnets
  187. ///
  188. /// This method removes all existing IPv6 subnets. It is used during
  189. /// reconfiguration - old configuration is wiped and new definitions
  190. /// are used to recreate subnets.
  191. ///
  192. /// @todo Implement more intelligent approach. Note that comparison
  193. /// between old and new configuration is tricky. For example: is
  194. /// 2000::/64 and 2000::/48 the same subnet or is it something
  195. /// completely new?
  196. void deleteSubnets6();
  197. /// @brief Returns pointer to the collection of all IPv4 subnets.
  198. ///
  199. /// This is used in a hook (subnet4_select), where the hook is able
  200. /// to choose a different subnet. Server code has to offer a list
  201. /// of possible choices (i.e. all subnets).
  202. /// @return a pointer to const Subnet4 collection
  203. const Subnet4Collection* getSubnets4() const {
  204. return (&subnets4_);
  205. }
  206. /// @brief returns const reference to all subnets6
  207. ///
  208. /// This is used in a hook (subnet6_select), where the hook is able
  209. /// to choose a different subnet. Server code has to offer a list
  210. /// of possible choices (i.e. all subnets).
  211. /// @return a pointer to const Subnet6 collection
  212. const Subnet6Collection* getSubnets6() {
  213. return (&subnets6_);
  214. }
  215. /// @brief get IPv4 subnet by address
  216. ///
  217. /// Finds a matching subnet, based on an address. This can be used
  218. /// in two cases: when trying to find an appropriate lease based on
  219. /// a) relay link address (that must be the address that is on link)
  220. /// b) our global address on the interface the message was received on
  221. /// (for directly connected clients)
  222. ///
  223. /// If there are any classes specified in a subnet, that subnet
  224. /// will be selected only if the client belongs to appropriate class.
  225. ///
  226. /// If relay is true then relay info overrides (i.e. value the sysadmin
  227. /// can configure in Dhcp4/subnet4[X]/relay/ip-address) can be used.
  228. /// That is true only for relays. Those overrides must not be used
  229. /// for client address or for client hints. They are for giaddr only.
  230. ///
  231. /// @param hint an address that belongs to a searched subnet
  232. /// @param classes classes the client belongs to
  233. /// @param relay true if address specified in hint is a relay
  234. ///
  235. /// @return a subnet object
  236. Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint,
  237. const isc::dhcp::ClientClasses& classes,
  238. bool relay = false) const;
  239. /// @brief Returns a subnet for the specified local interface.
  240. ///
  241. /// This function checks that the IP address assigned to the specified
  242. /// interface belongs to any IPv4 subnet configured, and returns this
  243. /// subnet.
  244. ///
  245. /// @todo Implement classes support here.
  246. ///
  247. /// @param iface Short name of the interface which is being checked.
  248. /// @param classes classes the client belongs to
  249. ///
  250. /// @return Pointer to the subnet matching interface specified or NULL
  251. /// pointer if IPv4 address on the interface doesn't match any subnet.
  252. Subnet4Ptr getSubnet4(const std::string& iface,
  253. const isc::dhcp::ClientClasses& classes) const;
  254. /// @brief adds a subnet4
  255. void addSubnet4(const Subnet4Ptr& subnet);
  256. /// @brief removes all IPv4 subnets
  257. ///
  258. /// This method removes all existing IPv4 subnets. It is used during
  259. /// reconfiguration - old configuration is wiped and new definitions
  260. /// are used to recreate subnets.
  261. ///
  262. /// @todo Implement more intelligent approach. Note that comparison
  263. /// between old and new configuration is tricky. For example: is
  264. /// 192.0.2.0/23 and 192.0.2.0/24 the same subnet or is it something
  265. /// completely new?
  266. void deleteSubnets4();
  267. /// @brief returns path do the data directory
  268. ///
  269. /// This method returns a path to writeable directory that DHCP servers
  270. /// can store data in.
  271. /// @return data directory
  272. std::string getDataDir();
  273. /// @brief Sets whether server should send back client-id in DHCPv4
  274. ///
  275. /// This is a compatibility flag. The default (true) is compliant with
  276. /// RFC6842. False is for backward compatibility.
  277. ///
  278. /// @param echo should the client-id be sent or not
  279. void echoClientId(const bool echo) {
  280. echo_v4_client_id_ = echo;
  281. }
  282. /// @brief Returns whether server should send back client-id in DHCPv4.
  283. /// @return true if client-id should be returned, false otherwise.
  284. bool echoClientId() const {
  285. return (echo_v4_client_id_);
  286. }
  287. /// @brief Updates the DHCP-DDNS client configuration to the given value.
  288. ///
  289. /// @param new_config pointer to the new client configuration.
  290. ///
  291. /// @throw Underlying method(s) will throw D2ClientError if given an empty
  292. /// pointer.
  293. void setD2ClientConfig(D2ClientConfigPtr& new_config);
  294. /// @brief Convenience method for checking if DHCP-DDNS updates are enabled.
  295. ///
  296. /// @return True if the D2 configuration is enabled.
  297. bool ddnsEnabled();
  298. /// @brief Fetches the DHCP-DDNS configuration pointer.
  299. ///
  300. /// @return a reference to the current configuration pointer.
  301. const D2ClientConfigPtr& getD2ClientConfig() const;
  302. /// @brief Fetches the DHCP-DDNS manager.
  303. ///
  304. /// @return a reference to the DHCP-DDNS manager.
  305. D2ClientMgr& getD2ClientMgr();
  306. /// @name Methods managing the collection of configurations.
  307. ///
  308. /// The following methods manage the process of preparing a configuration
  309. /// without affecting a currently used configuration and then commiting
  310. /// the configuration to replace current configuration atomically.
  311. /// They also allow for keeping a history of previous configurations so
  312. /// as the @c CfgMgr can revert to the historical configuration when
  313. /// required.
  314. ///
  315. /// @todo Migrate all configuration parameters to use the model supported
  316. /// by these functions.
  317. ///
  318. /// @todo Make the size of the configurations history configurable.
  319. ///
  320. //@{
  321. /// @brief Removes current, staging and all previous configurations.
  322. ///
  323. /// This function removes all configurations, including current and
  324. /// staging configurations. It creates a new current configuration with
  325. /// default settings.
  326. ///
  327. /// This function is exception safe.
  328. void clear();
  329. /// @brief Commits the staging configuration.
  330. ///
  331. /// The staging configuration becomes current configuration when this
  332. /// function is called. It removes the oldest configuration held in the
  333. /// history so as the size of the list of configuration does not exceed
  334. /// the @c CONFIG_LIST_SIZE.
  335. ///
  336. /// This function is exception safe.
  337. void commit();
  338. /// @brief Removes staging configuration.
  339. ///
  340. /// This function should be called when there is a staging configuration
  341. /// (likely created in the previous configuration attempt) but the entirely
  342. /// new configuration should be created. It removes the existing staging
  343. /// configuration and the next call to @c CfgMgr::getStagingCfg will return a
  344. /// fresh (default) configuration.
  345. ///
  346. /// This function is exception safe.
  347. void rollback();
  348. /// @brief Reverts to one of the previous configurations.
  349. ///
  350. /// This function reverts to selected previous configuration. The previous
  351. /// configuration is entirely copied to a new @c SrvConfig instance. This
  352. /// new instance has a unique sequence id (sequence id is not copied). The
  353. /// previous configuration (being copied) is not modified by this operation.
  354. ///
  355. /// The configuration to be copied is identified by the index value which
  356. /// is the distance between the current (most recent) and desired
  357. /// configuration. If the index is out of range an exception is thrown.
  358. ///
  359. /// @warning Revert operation will rollback any changes to the staging
  360. /// configuration (if it exists).
  361. ///
  362. /// @param index A distance from the current configuration to the
  363. /// past configuration to be reverted. The minimal value is 1 which points
  364. /// to the nearest configuration.
  365. ///
  366. /// @throw isc::OutOfRange if the specified index is out of range.
  367. void revert(const size_t index);
  368. /// @brief Returns a pointer to the current configuration.
  369. ///
  370. /// This function returns pointer to the current configuration. If the
  371. /// current configuration is not set it will create a default configuration
  372. /// and return it. Current configuration returned is read-only.
  373. ///
  374. /// @return Non-null const pointer to the current configuration.
  375. ConstSrvConfigPtr getCurrentCfg();
  376. /// @brief Returns a pointer to the staging configuration.
  377. ///
  378. /// The staging configuration is used by the configuration parsers to
  379. /// create new configuration. The staging configuration doesn't affect the
  380. /// server's operation until it is committed. The staging configuration
  381. /// is a non-const object which can be modified by the caller.
  382. ///
  383. /// Multiple consecutive calls to this function return the same object
  384. /// which can be modified from various places of the code (e.g. various
  385. /// configuration parsers).
  386. ///
  387. /// @return non-null pointer to the staging configuration.
  388. SrvConfigPtr getStagingCfg();
  389. //@}
  390. /// @name Methods setting/accessing global configuration for the process.
  391. ///
  392. //@{
  393. /// @brief Sets verbose mode.
  394. ///
  395. /// @param verbose A boolean value indicating if the process should run
  396. /// in verbose (true) or non-verbose mode.
  397. void setVerbose(const bool verbose) {
  398. verbose_mode_ = verbose;
  399. }
  400. /// @brief Checks if the process has been run in verbose mode.
  401. ///
  402. /// @return true if verbose mode enabled, false otherwise.
  403. bool isVerbose() const {
  404. return (verbose_mode_);
  405. }
  406. /// @brief Sets the default logger name.
  407. ///
  408. /// This name is used in cases when a user doesn't provide a configuration
  409. /// for logger in the Kea configuration file.
  410. void setDefaultLoggerName(const std::string& name) {
  411. default_logger_name_ = name;
  412. }
  413. /// @brief Returns default logger name.
  414. std::string getDefaultLoggerName() const {
  415. return (default_logger_name_);
  416. }
  417. //@}
  418. protected:
  419. /// @brief Protected constructor.
  420. ///
  421. /// This constructor is protected for 2 reasons. First, it forbids any
  422. /// instantiations of this class (CfgMgr is a singleton). Second, it
  423. /// allows derived class to instantiate it. That is useful for testing
  424. /// purposes.
  425. CfgMgr();
  426. /// @brief virtual destructor
  427. virtual ~CfgMgr();
  428. /// @brief a container for IPv6 subnets.
  429. ///
  430. /// That is a simple vector of pointers. It does not make much sense to
  431. /// optimize access time (e.g. using a map), because typical search
  432. /// pattern will use calling inRange() method on each subnet until
  433. /// a match is found.
  434. Subnet6Collection subnets6_;
  435. /// @brief a container for IPv4 subnets.
  436. ///
  437. /// That is a simple vector of pointers. It does not make much sense to
  438. /// optimize access time (e.g. using a map), because typical search
  439. /// pattern will use calling inRange() method on each subnet until
  440. /// a match is found.
  441. Subnet4Collection subnets4_;
  442. private:
  443. /// @brief Checks if current configuration is created and creates it if needed.
  444. ///
  445. /// This private method is called to ensure that the current configuration
  446. /// is created. If current configuration is not set, it creates the
  447. /// default current configuration.
  448. void ensureCurrentAllocated();
  449. /// @brief Checks that the IPv4 subnet with the given id already exists.
  450. ///
  451. /// @param subnet Subnet for which this function will check if the other
  452. /// subnet with equal id already exists.
  453. /// @return true if the duplicate subnet exists.
  454. bool isDuplicate(const Subnet4& subnet) const;
  455. /// @brief Checks that the IPv6 subnet with the given id already exists.
  456. ///
  457. /// @param subnet Subnet for which this function will check if the other
  458. /// subnet with equal id already exists.
  459. /// @return true if the duplicate subnet exists.
  460. bool isDuplicate(const Subnet6& subnet) const;
  461. /// @brief Container for defined DHCPv6 option spaces.
  462. OptionSpaceCollection spaces6_;
  463. /// @brief Container for defined DHCPv4 option spaces.
  464. OptionSpaceCollection spaces4_;
  465. /// @brief directory where data files (e.g. server-id) are stored
  466. std::string datadir_;
  467. /// Indicates whether v4 server should send back client-id
  468. bool echo_v4_client_id_;
  469. /// @brief Manages the DHCP-DDNS client and its configuration.
  470. D2ClientMgr d2_client_mgr_;
  471. /// @brief Server configuration
  472. ///
  473. /// This is a structure that will hold all configuration.
  474. /// @todo: migrate all other parameters to that structure.
  475. SrvConfigPtr configuration_;
  476. /// @name Configuration List.
  477. ///
  478. //@{
  479. /// @brief Server configuration list type.
  480. typedef std::list<SrvConfigPtr> SrvConfigList;
  481. /// @brief Container holding all previous and current configurations.
  482. SrvConfigList configs_;
  483. //@}
  484. /// @brief Indicates if a process has been ran in the verbose mode.
  485. bool verbose_mode_;
  486. /// @brief Default logger name.
  487. std::string default_logger_name_;
  488. };
  489. } // namespace isc::dhcp
  490. } // namespace isc
  491. #endif // CFGMGR_H