1 // Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef CFGMGR_H
8 #define CFGMGR_H
9 
10 #include <asiolink/io_address.h>
11 #include <dhcp/option.h>
12 #include <dhcp/option_space.h>
13 #include <dhcp/classify.h>
14 #include <dhcpsrv/d2_client_mgr.h>
15 #include <dhcpsrv/pool.h>
16 #include <dhcpsrv/srv_config.h>
17 #include <util/buffer.h>
18 #include <util/optional.h>
19 
20 #include <boost/shared_ptr.hpp>
21 #include <boost/noncopyable.hpp>
22 
23 #include <map>
24 #include <string>
25 #include <vector>
26 #include <list>
27 
28 namespace isc {
29 namespace dhcp {
30 
31 /// @brief Exception thrown when the same interface has been specified twice.
32 ///
33 /// In particular, this exception is thrown when adding interface to the set
34 /// of interfaces on which server is supposed to listen.
35 class DuplicateListeningIface : public Exception {
36 public:
DuplicateListeningIface(const char * file,size_t line,const char * what)37     DuplicateListeningIface(const char* file, size_t line, const char* what) :
38         isc::Exception(file, line, what) { };
39 };
40 
41 /// @brief Configuration Manager
42 ///
43 /// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
44 /// servers.
45 ///
46 /// Below is a sketch of configuration inheritance.
47 /// Let's investigate the following configuration:
48 ///
49 /// @code
50 /// preferred-lifetime 500;
51 /// valid-lifetime 1000;
52 /// subnet6 2001:db8:1::/48 {
53 ///     pool6 2001::db8:1::1 - 2001::db8:1::ff;
54 /// };
55 /// subnet6 2001:db8:2::/48 {
56 ///     valid-lifetime 2000;
57 ///     pool6 2001::db8:2::1 - 2001::db8:2::ff;
58 /// };
59 /// @endcode
60 ///
61 /// Parameters defined in a global scope are applicable to everything until
62 /// they are overwritten in a smaller scope, in this case subnet6.
63 /// In the example above, the first subnet6 has preferred lifetime of 500s
64 /// and a valid lifetime of 1000s. The second subnet has preferred lifetime
65 /// of 500s, but valid lifetime of 2000s.
66 ///
67 /// Parameter inheritance is implemented in dedicated classes. See
68 /// @ref isc::dhcp::SimpleParser4::deriveParameters and
69 /// @ref isc::dhcp::SimpleParser6::deriveParameters.
70 class CfgMgr : public boost::noncopyable {
71 public:
72 
73     /// @brief A number of configurations held by @c CfgMgr.
74     ///
75     /// @todo Make it configurable.
76     static const size_t CONFIG_LIST_SIZE;
77 
78     /// @brief returns a single instance of Configuration Manager
79     ///
80     /// CfgMgr is a singleton and this method is the only way of
81     /// accessing it.
82     static CfgMgr& instance();
83 
84     /// @brief returns path do the data directory
85     ///
86     /// This method returns a path to writable directory that DHCP servers
87     /// can store data in.
88     /// @return data directory
89     util::Optional<std::string> getDataDir() const;
90 
91     /// @brief Sets new data directory.
92     ///
93     /// @param datadir New data directory.
94     /// @param unspecified Initial state. Default is "unspecified".
95     void setDataDir(const std::string& datadir, bool unspecified = true);
96 
97     /// @brief Updates the DHCP-DDNS client configuration to the given value.
98     ///
99     /// Passes the new configuration to the D2ClientMgr instance,
100     /// d2_client_mgr_, which will attempt to apply the new configuration
101     /// by shutting down its sender and opening a new connection per the new
102     /// configuration (see @c D2ClientMgr::setD2ClientConfig()).
103     ///
104     /// @param new_config pointer to the new client configuration.
105     ///
106     /// @throw Underlying method(s) will throw D2ClientError if given an empty
107     /// pointer.
108     void setD2ClientConfig(D2ClientConfigPtr& new_config);
109 
110     /// @brief Convenience method for checking if DHCP-DDNS updates are enabled.
111     ///
112     /// @return True if the D2 configuration is enabled.
113     bool ddnsEnabled();
114 
115     /// @brief Fetches the DHCP-DDNS configuration pointer.
116     ///
117     /// @return a reference to the current configuration pointer.
118     const D2ClientConfigPtr& getD2ClientConfig() const;
119 
120     /// @brief Fetches the DHCP-DDNS manager.
121     ///
122     /// @return a reference to the DHCP-DDNS manager.
123     D2ClientMgr& getD2ClientMgr();
124 
125     /// @name Methods managing the collection of configurations.
126     ///
127     /// The following methods manage the process of preparing a configuration
128     /// without affecting a currently used configuration and then committing
129     /// the configuration to replace current configuration atomically.
130     /// They also allow for keeping a history of previous configurations so
131     /// as the @c CfgMgr can revert to the historical configuration when
132     /// required.
133     ///
134     /// @todo Migrate all configuration parameters to use the model supported
135     /// by these functions.
136     ///
137     /// @todo Make the size of the configurations history configurable.
138     ///
139     //@{
140 
141     /// @brief Removes current, staging and all previous configurations.
142     ///
143     /// This function removes all configurations, including current,
144     /// staging and external configurations. It creates a new current
145     /// configuration with default settings.
146     ///
147     /// This function is exception safe.
148     void clear();
149 
150     /// @brief Commits the staging configuration.
151     ///
152     /// The staging configuration becomes current configuration when this
153     /// function is called. It removes the oldest configuration held in the
154     /// history so as the size of the list of configuration does not exceed
155     /// the @c CONFIG_LIST_SIZE.
156     ///
157     /// This function is exception safe.
158     void commit();
159 
160     /// @brief Removes staging configuration.
161     ///
162     /// This function should be called when there is a staging configuration
163     /// (likely created in the previous configuration attempt) but the entirely
164     /// new configuration should be created. It removes the existing staging
165     /// configuration and the next call to @c CfgMgr::getStagingCfg will return a
166     /// fresh (default) configuration.
167     ///
168     /// This function is exception safe.
169     void rollback();
170 
171     /// @brief Reverts to one of the previous configurations.
172     ///
173     /// This function reverts to selected previous configuration. The previous
174     /// configuration is entirely copied to a new @c SrvConfig instance. This
175     /// new instance has a unique sequence id (sequence id is not copied). The
176     /// previous configuration (being copied) is not modified by this operation.
177     ///
178     /// The configuration to be copied is identified by the index value which
179     /// is the distance between the current (most recent) and desired
180     /// configuration. If the index is out of range an exception is thrown.
181     ///
182     /// @warning Revert operation will rollback any changes to the staging
183     /// configuration (if it exists).
184     ///
185     /// @warning This function requires that the entire previous configuration
186     /// is copied to the new configuration object. This is not working for
187     /// some of the complex configuration objects, e.g. subnets. Hence, the
188     /// "revert" operation is not really usable at this point.
189     ///
190     /// @param index A distance from the current configuration to the
191     /// past configuration to be reverted. The minimal value is 1 which points
192     /// to the nearest configuration.
193     ///
194     /// @throw isc::OutOfRange if the specified index is out of range.
195     void revert(const size_t index);
196 
197     /// @brief Returns a pointer to the current configuration.
198     ///
199     /// This function returns pointer to the current configuration. If the
200     /// current configuration is not set it will create a default configuration
201     /// and return it.
202     ///
203     /// In the previous Kea releases this method used to return a const pointer
204     /// to the current configuration to ensure that it is not accidentally
205     /// modified while the server is running. This has been changed in Kea 1.3
206     /// release and now this function returns a non-const pointer. The reason
207     /// is that there are certain use cases when current configuration must
208     /// be modified without going through a full cycle of server
209     /// reconfiguration, e.g. add a subnet to the current configuration as
210     /// a result of receiving a command over control API. In such case the
211     /// performance of processing such command is critical and rebuilding the
212     /// whole configuration just for this small configuration change is out
213     /// of question.
214     ///
215     /// Nevertheless, such configuration updates should always be made with
216     /// caution and one has to make sure that the configuration data integrity
217     /// is preserved.
218     ///
219     /// @return Non-null pointer to the current configuration.
220     SrvConfigPtr getCurrentCfg();
221 
222     /// @brief Returns a pointer to the staging configuration.
223     ///
224     /// The staging configuration is used by the configuration parsers to
225     /// create new configuration. The staging configuration doesn't affect the
226     /// server's operation until it is committed. The staging configuration
227     /// is a non-const object which can be modified by the caller.
228     ///
229     /// Multiple consecutive calls to this function return the same object
230     /// which can be modified from various places of the code (e.g. various
231     /// configuration parsers).
232     ///
233     /// @return non-null pointer to the staging configuration.
234     SrvConfigPtr getStagingCfg();
235 
236     /// @brief Creates an external configuration and returns pointer to it.
237     ///
238     /// External configurations are those that come from other sources than
239     /// from the configuration file, e.g. a database or a command. They
240     /// are created aside and merged into the staging or current configuration.
241     /// External configurations are accessed by their sequence numbers. The
242     /// sequence numbers are autogenerated when the external configuration
243     /// instance is created.
244     ///
245     /// @return non-null pointer to created external configuration.
246     SrvConfigPtr createExternalCfg();
247 
248     /// @brief Merges external configuration with the given sequence number
249     /// into the staging configuration.
250     ///
251     /// After the merge, the source configuration is discarded from the
252     /// @c CfgMgr as it should not be used anymore.
253     ///
254     /// @param seq Source configuration sequence number.
255     ///
256     /// @throw BadValue if the external configuration with the given sequence
257     /// number doesn't exist.
258     void mergeIntoStagingCfg(const uint32_t seq);
259 
260     /// @brief Merges external configuration with the given sequence number
261     /// into the current configuration.
262     ///
263     /// After the merge, the source configuration is discarded from the
264     /// @c CfgMgr as it should not be used anymore.
265     ///
266     /// @param seq Source configuration sequence number.
267     ///
268     /// @throw BadValue if the external configuration with the given sequence
269     /// number doesn't exist.
270     void mergeIntoCurrentCfg(const uint32_t seq);
271 
272     //@}
273 
274     /// @brief Sets address family (AF_INET or AF_INET6)
setFamily(uint16_t family)275     void setFamily(uint16_t family) {
276         family_ = family == AF_INET ? AF_INET : AF_INET6;
277     }
278 
279     /// @brief Returns address family.
getFamily()280     uint16_t getFamily() const {
281         return (family_);
282     }
283 
284     //@}
285 
286 protected:
287 
288     /// @brief Protected constructor.
289     ///
290     /// This constructor is protected for 2 reasons. First, it forbids any
291     /// instantiations of this class (CfgMgr is a singleton). Second, it
292     /// allows derived class to instantiate it. That is useful for testing
293     /// purposes.
294     CfgMgr();
295 
296     /// @brief virtual destructor
297     virtual ~CfgMgr();
298 
299 private:
300 
301     /// @brief Checks if current configuration is created and creates it if needed.
302     ///
303     /// This private method is called to ensure that the current configuration
304     /// is created. If current configuration is not set, it creates the
305     /// default current configuration.
306     void ensureCurrentAllocated();
307 
308 
309     /// @brief Merges external configuration with the given sequence number
310     /// into the specified configuration.
311     ///
312     /// @param target_config Pointer to the configuration into which the
313     /// external configuration should be merged.
314     /// @param seq Source configuration sequence number.
315     void mergeIntoCfg(const SrvConfigPtr& taget_config, const uint32_t seq);
316 
317     /// @brief directory where data files (e.g. server-id) are stored
318     util::Optional<std::string> datadir_;
319 
320     /// @brief Manages the DHCP-DDNS client and its configuration.
321     D2ClientMgr d2_client_mgr_;
322 
323     /// @brief Server configuration
324     ///
325     /// This is a structure that will hold all configuration.
326     /// @todo: migrate all other parameters to that structure.
327     SrvConfigPtr configuration_;
328 
329     /// @name Configuration List.
330     ///
331     //@{
332     /// @brief Server configuration list type.
333     typedef std::list<SrvConfigPtr> SrvConfigList;
334 
335     /// @brief Container holding all previous and current configurations.
336     SrvConfigList configs_;
337     //@}
338 
339     /// @name Map of external configurations.
340     ///
341     //@{
342     /// @brief Server configuration map type.
343     typedef std::map<uint32_t, SrvConfigPtr> SrvConfigMap;
344 
345     /// @brief Map of external configurations with sequence numbers used
346     /// as keys.
347     SrvConfigMap external_configs_;
348     //@}
349 
350     /// @brief Address family.
351     uint16_t family_;
352 };
353 
354 } // namespace isc::dhcp
355 } // namespace isc
356 
357 #endif // CFGMGR_H
358