cfgmgr.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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_definition.h>
  19. #include <dhcp/option_space.h>
  20. #include <dhcp/classify.h>
  21. #include <dhcpsrv/d2_client_mgr.h>
  22. #include <dhcpsrv/option_space_container.h>
  23. #include <dhcpsrv/pool.h>
  24. #include <dhcpsrv/subnet.h>
  25. #include <dhcpsrv/configuration.h>
  26. #include <util/buffer.h>
  27. #include <boost/shared_ptr.hpp>
  28. #include <boost/noncopyable.hpp>
  29. #include <map>
  30. #include <string>
  31. #include <vector>
  32. #include <list>
  33. namespace isc {
  34. namespace dhcp {
  35. /// @brief Exception thrown when the same interface has been specified twice.
  36. ///
  37. /// In particular, this exception is thrown when adding interface to the set
  38. /// of interfaces on which server is supposed to listen.
  39. class DuplicateListeningIface : public Exception {
  40. public:
  41. DuplicateListeningIface(const char* file, size_t line, const char* what) :
  42. isc::Exception(file, line, what) { };
  43. };
  44. /// @brief Exception thrown upon attempt to add subnet with an ID that belongs
  45. /// to the subnet that already exists.
  46. class DuplicateSubnetID : public Exception {
  47. public:
  48. DuplicateSubnetID(const char* file, size_t line, const char* what) :
  49. isc::Exception(file, line, what) { };
  50. };
  51. /// @brief Configuration Manager
  52. ///
  53. /// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
  54. /// servers. It currently holds information about zero or more subnets6.
  55. /// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
  56. /// basic "chunk" of configuration. It contains a range of assignable
  57. /// addresses.
  58. ///
  59. /// Below is a sketch of configuration inheritance (not implemented yet).
  60. /// Let's investigate the following configuration:
  61. ///
  62. /// @code
  63. /// preferred-lifetime 500;
  64. /// valid-lifetime 1000;
  65. /// subnet6 2001:db8:1::/48 {
  66. /// pool6 2001::db8:1::1 - 2001::db8:1::ff;
  67. /// };
  68. /// subnet6 2001:db8:2::/48 {
  69. /// valid-lifetime 2000;
  70. /// pool6 2001::db8:2::1 - 2001::db8:2::ff;
  71. /// };
  72. /// @endcode
  73. ///
  74. /// Parameters defined in a global scope are applicable to everything until
  75. /// they are overwritten in a smaller scope, in this case subnet6.
  76. /// In the example above, the first subnet6 has preferred lifetime of 500s
  77. /// and a valid lifetime of 1000s. The second subnet has preferred lifetime
  78. /// of 500s, but valid lifetime of 2000s.
  79. ///
  80. /// Parameter inheritance is likely to be implemented in configuration handling
  81. /// routines, so there is no storage capability in a global scope for
  82. /// subnet-specific parameters.
  83. ///
  84. /// @todo: Implement Subnet4 support (ticket #2237)
  85. /// @todo: Implement option definition support
  86. /// @todo: Implement parameter inheritance
  87. class CfgMgr : public boost::noncopyable {
  88. public:
  89. /// @brief returns a single instance of Configuration Manager
  90. ///
  91. /// CfgMgr is a singleton and this method is the only way of
  92. /// accessing it.
  93. static CfgMgr& instance();
  94. /// @brief Add new option definition.
  95. ///
  96. /// @param def option definition to be added.
  97. /// @param option_space name of the option space to add definition to.
  98. ///
  99. /// @throw isc::dhcp::DuplicateOptionDefinition when the particular
  100. /// option definition already exists.
  101. /// @throw isc::dhcp::MalformedOptionDefinition when the pointer to
  102. /// an option definition is NULL.
  103. /// @throw isc::BadValue when the option space name is empty or
  104. /// when trying to override the standard option (in dhcp4 or dhcp6
  105. /// option space).
  106. void addOptionDef(const OptionDefinitionPtr& def,
  107. const std::string& option_space);
  108. /// @brief Return option definitions for particular option space.
  109. ///
  110. /// @param option_space option space.
  111. ///
  112. /// @return pointer to the collection of option definitions for
  113. /// the particular option space. The option collection is empty
  114. /// if no option exists for the option space specified.
  115. OptionDefContainerPtr
  116. getOptionDefs(const std::string& option_space) const;
  117. /// @brief Return option definition for a particular option space and code.
  118. ///
  119. /// @param option_space option space.
  120. /// @param option_code option code.
  121. ///
  122. /// @return an option definition or NULL pointer if option definition
  123. /// has not been found.
  124. OptionDefinitionPtr getOptionDef(const std::string& option_space,
  125. const uint16_t option_code) const;
  126. /// @brief Adds new DHCPv4 option space to the collection.
  127. ///
  128. /// @param space option space to be added.
  129. ///
  130. /// @throw isc::dhcp::InvalidOptionSpace invalid option space
  131. /// has been specified.
  132. void addOptionSpace4(const OptionSpacePtr& space);
  133. /// @brief Adds new DHCPv6 option space to the collection.
  134. ///
  135. /// @param space option space to be added.
  136. ///
  137. /// @throw isc::dhcp::InvalidOptionSpace invalid option space
  138. /// has been specified.
  139. void addOptionSpace6(const OptionSpacePtr& space);
  140. /// @brief Return option spaces for DHCPv4.
  141. ///
  142. /// @return A collection of option spaces.
  143. const OptionSpaceCollection& getOptionSpaces4() const {
  144. return (spaces4_);
  145. }
  146. /// @brief Return option spaces for DHCPv6.
  147. ///
  148. /// @return A collection of option spaces.
  149. const OptionSpaceCollection& getOptionSpaces6() const {
  150. return (spaces6_);
  151. }
  152. /// @brief get IPv6 subnet by address
  153. ///
  154. /// Finds a matching subnet, based on an address. This can be used
  155. /// in two cases: when trying to find an appropriate lease based on
  156. /// a) relay link address (that must be the address that is on link)
  157. /// b) our global address on the interface the message was received on
  158. /// (for directly connected clients)
  159. ///
  160. /// If there are any classes specified in a subnet, that subnet
  161. /// will be selected only if the client belongs to appropriate class.
  162. ///
  163. /// @note The client classification is checked before any relay
  164. /// information checks are conducted.
  165. ///
  166. /// If relay is true then relay info overrides (i.e. value the sysadmin
  167. /// can configure in Dhcp6/subnet6[X]/relay/ip-address) can be used.
  168. /// That is applicable only for relays. Those overrides must not be used
  169. /// for client address or for client hints. They are for link-addr field
  170. /// in the RELAY_FORW message only.
  171. ///
  172. /// @param hint an address that belongs to a searched subnet
  173. /// @param classes classes the client belongs to
  174. /// @param relay true if address specified in hint is a relay
  175. ///
  176. /// @return a subnet object (or NULL if no suitable match was fount)
  177. Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint,
  178. const isc::dhcp::ClientClasses& classes,
  179. const bool relay = false);
  180. /// @brief get IPv6 subnet by interface name
  181. ///
  182. /// Finds a matching local subnet, based on interface name. This
  183. /// is used for selecting subnets that were explicitly marked by the
  184. /// user as reachable over specified network interface.
  185. ///
  186. /// If there are any classes specified in a subnet, that subnet
  187. /// will be selected only if the client belongs to appropriate class.
  188. ///
  189. /// @param iface_name interface name
  190. /// @param classes classes the client belongs to
  191. ///
  192. /// @return a subnet object (or NULL if no suitable match was fount)
  193. Subnet6Ptr getSubnet6(const std::string& iface_name,
  194. const isc::dhcp::ClientClasses& classes);
  195. /// @brief get IPv6 subnet by interface-id
  196. ///
  197. /// Another possibility to find a subnet is based on interface-id.
  198. ///
  199. /// If there are any classes specified in a subnet, that subnet
  200. /// will be selected only if the client belongs to appropriate class.
  201. ///
  202. /// @param interface_id content of interface-id option returned by a relay
  203. /// @param classes classes the client belongs to
  204. ///
  205. /// @return a subnet object
  206. Subnet6Ptr getSubnet6(OptionPtr interface_id,
  207. const isc::dhcp::ClientClasses& classes);
  208. /// @brief adds an IPv6 subnet
  209. ///
  210. /// @param subnet new subnet to be added.
  211. void addSubnet6(const Subnet6Ptr& subnet);
  212. /// @brief Delete all option definitions.
  213. void deleteOptionDefs();
  214. /// @todo: Add subnet6 removal routines. Currently it is not possible
  215. /// to remove subnets. The only case where subnet6 removal would be
  216. /// needed is a dynamic server reconfiguration - a use case that is not
  217. /// planned to be supported any time soon.
  218. /// @brief removes all IPv6 subnets
  219. ///
  220. /// This method removes all existing IPv6 subnets. It is used during
  221. /// reconfiguration - old configuration is wiped and new definitions
  222. /// are used to recreate subnets.
  223. ///
  224. /// @todo Implement more intelligent approach. Note that comparison
  225. /// between old and new configuration is tricky. For example: is
  226. /// 2000::/64 and 2000::/48 the same subnet or is it something
  227. /// completely new?
  228. void deleteSubnets6();
  229. /// @brief returns const reference to all subnets6
  230. ///
  231. /// This is used in a hook (subnet4_select), where the hook is able
  232. /// to choose a different subnet. Server code has to offer a list
  233. /// of possible choices (i.e. all subnets).
  234. /// @return a pointer to const Subnet6 collection
  235. const Subnet4Collection* getSubnets4() const {
  236. return (&subnets4_);
  237. }
  238. /// @brief returns const reference to all subnets6
  239. ///
  240. /// This is used in a hook (subnet6_select), where the hook is able
  241. /// to choose a different subnet. Server code has to offer a list
  242. /// of possible choices (i.e. all subnets).
  243. /// @return a pointer to const Subnet6 collection
  244. const Subnet6Collection* getSubnets6() {
  245. return (&subnets6_);
  246. }
  247. /// @brief get IPv4 subnet by address
  248. ///
  249. /// Finds a matching subnet, based on an address. This can be used
  250. /// in two cases: when trying to find an appropriate lease based on
  251. /// a) relay link address (that must be the address that is on link)
  252. /// b) our global address on the interface the message was received on
  253. /// (for directly connected clients)
  254. ///
  255. /// If there are any classes specified in a subnet, that subnet
  256. /// will be selected only if the client belongs to appropriate class.
  257. ///
  258. /// If relay is true then relay info overrides (i.e. value the sysadmin
  259. /// can configure in Dhcp4/subnet4[X]/relay/ip-address) can be used.
  260. /// That is true only for relays. Those overrides must not be used
  261. /// for client address or for client hints. They are for giaddr only.
  262. ///
  263. /// @param hint an address that belongs to a searched subnet
  264. /// @param classes classes the client belongs to
  265. /// @param relay true if address specified in hint is a relay
  266. ///
  267. /// @return a subnet object
  268. Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint,
  269. const isc::dhcp::ClientClasses& classes,
  270. bool relay = false) const;
  271. /// @brief Returns a subnet for the specified local interface.
  272. ///
  273. /// This function checks that the IP address assigned to the specified
  274. /// interface belongs to any IPv4 subnet configured, and returns this
  275. /// subnet.
  276. ///
  277. /// @todo Implement classes support here.
  278. ///
  279. /// @param iface Short name of the interface which is being checked.
  280. /// @param classes classes the client belongs to
  281. ///
  282. /// @return Pointer to the subnet matching interface specified or NULL
  283. /// pointer if IPv4 address on the interface doesn't match any subnet.
  284. Subnet4Ptr getSubnet4(const std::string& iface,
  285. const isc::dhcp::ClientClasses& classes) const;
  286. /// @brief adds a subnet4
  287. void addSubnet4(const Subnet4Ptr& subnet);
  288. /// @brief removes all IPv4 subnets
  289. ///
  290. /// This method removes all existing IPv4 subnets. It is used during
  291. /// reconfiguration - old configuration is wiped and new definitions
  292. /// are used to recreate subnets.
  293. ///
  294. /// @todo Implement more intelligent approach. Note that comparison
  295. /// between old and new configuration is tricky. For example: is
  296. /// 192.0.2.0/23 and 192.0.2.0/24 the same subnet or is it something
  297. /// completely new?
  298. void deleteSubnets4();
  299. /// @brief returns path do the data directory
  300. ///
  301. /// This method returns a path to writeable directory that DHCP servers
  302. /// can store data in.
  303. /// @return data directory
  304. std::string getDataDir();
  305. /// @brief Sets whether server should send back client-id in DHCPv4
  306. ///
  307. /// This is a compatibility flag. The default (true) is compliant with
  308. /// RFC6842. False is for backward compatibility.
  309. ///
  310. /// @param echo should the client-id be sent or not
  311. void echoClientId(const bool echo) {
  312. echo_v4_client_id_ = echo;
  313. }
  314. /// @brief Returns whether server should send back client-id in DHCPv4.
  315. /// @return true if client-id should be returned, false otherwise.
  316. bool echoClientId() const {
  317. return (echo_v4_client_id_);
  318. }
  319. /// @brief Updates the DHCP-DDNS client configuration to the given value.
  320. ///
  321. /// @param new_config pointer to the new client configuration.
  322. ///
  323. /// @throw Underlying method(s) will throw D2ClientError if given an empty
  324. /// pointer.
  325. void setD2ClientConfig(D2ClientConfigPtr& new_config);
  326. /// @brief Convenience method for checking if DHCP-DDNS updates are enabled.
  327. ///
  328. /// @return True if the D2 configuration is enabled.
  329. bool ddnsEnabled();
  330. /// @brief Fetches the DHCP-DDNS configuration pointer.
  331. ///
  332. /// @return a reference to the current configuration pointer.
  333. const D2ClientConfigPtr& getD2ClientConfig() const;
  334. /// @brief Fetches the DHCP-DDNS manager.
  335. ///
  336. /// @return a reference to the DHCP-DDNS manager.
  337. D2ClientMgr& getD2ClientMgr();
  338. /// @brief Returns the current configuration.
  339. ///
  340. /// @return a pointer to the current configuration.
  341. ConfigurationPtr getConfiguration();
  342. protected:
  343. /// @brief Protected constructor.
  344. ///
  345. /// This constructor is protected for 2 reasons. First, it forbids any
  346. /// instantiations of this class (CfgMgr is a singleton). Second, it
  347. /// allows derived class to instantiate it. That is useful for testing
  348. /// purposes.
  349. CfgMgr();
  350. /// @brief virtual destructor
  351. virtual ~CfgMgr();
  352. /// @brief a container for IPv6 subnets.
  353. ///
  354. /// That is a simple vector of pointers. It does not make much sense to
  355. /// optimize access time (e.g. using a map), because typical search
  356. /// pattern will use calling inRange() method on each subnet until
  357. /// a match is found.
  358. Subnet6Collection subnets6_;
  359. /// @brief a container for IPv4 subnets.
  360. ///
  361. /// That is a simple vector of pointers. It does not make much sense to
  362. /// optimize access time (e.g. using a map), because typical search
  363. /// pattern will use calling inRange() method on each subnet until
  364. /// a match is found.
  365. Subnet4Collection subnets4_;
  366. private:
  367. /// @brief Checks that the IPv4 subnet with the given id already exists.
  368. ///
  369. /// @param subnet Subnet for which this function will check if the other
  370. /// subnet with equal id already exists.
  371. /// @return true if the duplicate subnet exists.
  372. bool isDuplicate(const Subnet4& subnet) const;
  373. /// @brief Checks that the IPv6 subnet with the given id already exists.
  374. ///
  375. /// @param subnet Subnet for which this function will check if the other
  376. /// subnet with equal id already exists.
  377. /// @return true if the duplicate subnet exists.
  378. bool isDuplicate(const Subnet6& subnet) const;
  379. /// @brief A collection of option definitions.
  380. ///
  381. /// A collection of option definitions that can be accessed
  382. /// using option space name they belong to.
  383. OptionSpaceContainer<OptionDefContainer,
  384. OptionDefinitionPtr, std::string> option_def_spaces_;
  385. /// @brief Container for defined DHCPv6 option spaces.
  386. OptionSpaceCollection spaces6_;
  387. /// @brief Container for defined DHCPv4 option spaces.
  388. OptionSpaceCollection spaces4_;
  389. /// @brief directory where data files (e.g. server-id) are stored
  390. std::string datadir_;
  391. /// Indicates whether v4 server should send back client-id
  392. bool echo_v4_client_id_;
  393. /// @brief Manages the DHCP-DDNS client and its configuration.
  394. D2ClientMgr d2_client_mgr_;
  395. /// @brief Configuration
  396. ///
  397. /// This is a structure that will hold all configuration.
  398. /// @todo: migrate all other parameters to that structure.
  399. /// @todo: maybe this should be a vector<Configuration>, so we could keep
  400. /// previous configurations and do a rollback if needed?
  401. ConfigurationPtr configuration_;
  402. };
  403. } // namespace isc::dhcp
  404. } // namespace isc
  405. #endif // CFGMGR_H