Kea  1.9.9-git
d2_simple_parser.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2021 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 #include <config.h>
8 
9 #include <d2/d2_config.h>
10 #include <d2/d2_simple_parser.h>
11 #include <cc/data.h>
12 #include <hooks/hooks_manager.h>
13 #include <hooks/hooks_parser.h>
14 #include <boost/foreach.hpp>
15 
16 using namespace isc::data;
17 using namespace isc::d2;
18 using namespace isc;
19 
20 namespace {
21 
23 getProtocol(ConstElementPtr map, const std::string& name) {
24  ConstElementPtr value = map->get(name);
25  if (!value) {
26  isc_throw(D2CfgError, "Mandatory parameter " << name
27  << " not found (" << map->getPosition() << ")");
28  }
29  std::string str = value->stringValue();
30  try {
31  return (dhcp_ddns::stringToNcrProtocol(str));
32  } catch (const std::exception& ex) {
34  "invalid NameChangeRequest protocol (" << str
35  << ") specified for parameter '" << name
36  << "' (" << value->getPosition() << ")");
37  }
38 }
39 
41 getFormat(ConstElementPtr map, const std::string& name) {
42  ConstElementPtr value = map->get(name);
43  if (!value) {
44  isc_throw(D2CfgError, "Mandatory parameter " << name
45  << " not found (" << map->getPosition() << ")");
46  }
47  std::string str = value->stringValue();
48  try {
49  return (dhcp_ddns::stringToNcrFormat(str));
50  } catch (const std::exception& ex) {
52  "invalid NameChangeRequest format (" << str
53  << ") specified for parameter '" << name
54  << "' (" << value->getPosition() << ")");
55  }
56 }
57 
58 } // anon
59 
60 namespace isc {
61 namespace d2 {
76 
82 const SimpleDefaults D2SimpleParser::D2_GLOBAL_DEFAULTS = {
83  { "ip-address", Element::string, "127.0.0.1" },
84  { "port", Element::integer, "53001" },
85  { "dns-server-timeout", Element::integer, "100" }, // in seconds
86  { "ncr-protocol", Element::string, "UDP" },
87  { "ncr-format", Element::string, "JSON" }
88 };
89 
91 const SimpleDefaults D2SimpleParser::TSIG_KEY_DEFAULTS = {
92  { "digest-bits", Element::integer, "0" }
93 };
94 
101 const SimpleDefaults D2SimpleParser::DDNS_DOMAIN_MGR_DEFAULTS = {
102 };
103 
105 const SimpleDefaults D2SimpleParser::DDNS_DOMAIN_DEFAULTS = {
106  { "key-name", Element::string, "" }
107 };
108 
110 const SimpleDefaults D2SimpleParser::DNS_SERVER_DEFAULTS = {
111  { "hostname", Element::string, "" },
112  { "port", Element::integer, "53" },
113 };
114 
116 
120 
121 size_t
122 D2SimpleParser::setAllDefaults(isc::data::ElementPtr global) {
123  size_t cnt = 0;
124  // Set global defaults first.
125  cnt = setDefaults(global, D2_GLOBAL_DEFAULTS);
126 
127  // If the key list is present, set its members' defaults
128  if (global->find("tsig-keys")) {
129  ConstElementPtr keys = global->get("tsig-keys");
130  cnt += setListDefaults(keys, TSIG_KEY_DEFAULTS);
131  } else {
132  // Not present, so add an empty list.
133  ConstElementPtr list(new ListElement());
134  global->set("tsig-keys", list);
135  cnt++;
136  }
137 
138  // Set the forward domain manager defaults.
139  cnt += setManagerDefaults(global, "forward-ddns", DDNS_DOMAIN_MGR_DEFAULTS);
140 
141  // Set the reverse domain manager defaults.
142  cnt += setManagerDefaults(global, "reverse-ddns", DDNS_DOMAIN_MGR_DEFAULTS);
143  return (cnt);
144 }
145 
146 size_t
147 D2SimpleParser::setDdnsDomainDefaults(ElementPtr domain,
148  const SimpleDefaults& domain_defaults) {
149  size_t cnt = 0;
150 
151  // Set the domain's scalar defaults
152  cnt += setDefaults(domain, domain_defaults);
153  if (domain->find("dns-servers")) {
154  // Now add the defaults to its server list.
155  ConstElementPtr servers = domain->get("dns-servers");
156  cnt += setListDefaults(servers, DNS_SERVER_DEFAULTS);
157  }
158 
159  return (cnt);
160 }
161 
162 
163 size_t
164 D2SimpleParser::setManagerDefaults(ElementPtr global,
165  const std::string& mgr_name,
166  const SimpleDefaults& mgr_defaults) {
167  size_t cnt = 0;
168 
169  if (!global->find(mgr_name)) {
170  // If it's not present, then default is an empty map
171  ConstElementPtr map(new MapElement());
172  global->set(mgr_name, map);
173  ++cnt;
174  } else {
175  // Get a writable copy of the manager element map
176  ElementPtr mgr =
177  boost::const_pointer_cast<Element>(global->get(mgr_name));
178 
179  // Set the manager's scalar defaults first
180  cnt += setDefaults(mgr, mgr_defaults);
181 
182  // Get the domain list and set defaults for them.
183  // The domain list may not be present ddns for this
184  // manager is disabled.
185  if (mgr->find("ddns-domains")) {
186  ConstElementPtr domains = mgr->get("ddns-domains");
187  BOOST_FOREACH(ElementPtr domain, domains->listValue()) {
188  // Set the domain's defaults. We can't use setListDefaults()
189  // as this does not handle sub-lists or maps, like server list.
190  cnt += setDdnsDomainDefaults(domain, DDNS_DOMAIN_DEFAULTS);
191  }
192  }
193 
194  }
195 
196  return (cnt);
197 }
198 
199 void D2SimpleParser::parse(const D2CfgContextPtr& ctx,
200  const isc::data::ConstElementPtr& config,
201  bool check_only) {
202  // TSIG keys need to parse before the Domains, so we can catch Domains
203  // that specify undefined keys. Create the necessary parsing order now.
204  // addToParseOrder("tsig-keys");
205  // addToParseOrder("forward-ddns");
206  // addToParseOrder("reverse-ddns");
207 
208  ConstElementPtr keys = config->get("tsig-keys");
209  if (keys) {
210  TSIGKeyInfoListParser parser;
211  ctx->setKeys(parser.parse(keys));
212  }
213 
214  ConstElementPtr fwd = config->get("forward-ddns");
215  if (fwd) {
217  DdnsDomainListMgrPtr mgr = parser.parse(fwd, "forward-ddns",
218  ctx->getKeys());
219  ctx->setForwardMgr(mgr);
220  }
221 
222  ConstElementPtr rev = config->get("reverse-ddns");
223  if (rev) {
225  DdnsDomainListMgrPtr mgr = parser.parse(rev, "reverse-ddns",
226  ctx->getKeys());
227  ctx->setReverseMgr(mgr);
228  }
229 
230  // Fetch the parameters in the config, performing any logical
231  // validation required.
232  asiolink::IOAddress ip_address(0);
233  uint32_t port = 0;
234  uint32_t dns_server_timeout = 0;
237 
238  ip_address = SimpleParser::getAddress(config, "ip-address");
239 
240  if ((ip_address.toText() == "0.0.0.0") ||
241  (ip_address.toText() == "::")) {
242  isc_throw(D2CfgError, "IP address cannot be \""
243  << ip_address << "\""
244  << " (" << config->get("ip-address")->getPosition() << ")");
245  }
246 
247  port = SimpleParser::getUint32(config, "port");
248 
249  dns_server_timeout = SimpleParser::getUint32(config, "dns-server-timeout");
250 
251  ncr_protocol = getProtocol(config, "ncr-protocol");
252  if (ncr_protocol != dhcp_ddns::NCR_UDP) {
253  isc_throw(D2CfgError, "ncr-protocol : "
254  << dhcp_ddns::ncrProtocolToString(ncr_protocol)
255  << " is not yet supported ("
256  << config->get("ncr-protocol")->getPosition() << ")");
257  }
258 
259  ncr_format = getFormat(config, "ncr-format");
260  if (ncr_format != dhcp_ddns::FMT_JSON) {
261  isc_throw(D2CfgError, "NCR Format:"
262  << dhcp_ddns::ncrFormatToString(ncr_format)
263  << " is not yet supported"
264  << " (" << config->get("ncr-format")->getPosition() << ")");
265  }
266 
267  ConstElementPtr user = config->get("user-context");
268  if (user) {
269  ctx->setContext(user);
270  }
271 
272  ConstElementPtr socket = config->get("control-socket");
273  if (socket) {
274  if (socket->getType() != Element::map) {
275  isc_throw(D2CfgError, "Specified control-socket is expected to be a map"
276  ", i.e. a structure defined within { }");
277  }
278  ctx->setControlSocketInfo(socket);
279  }
280 
281  // Finally, let's get the hook libs!
282  using namespace isc::hooks;
283  HooksConfig& libraries = ctx->getHooksConfig();
284  ConstElementPtr hooks = config->get("hooks-libraries");
285  if (hooks) {
286  HooksLibrariesParser hooks_parser;
287  hooks_parser.parse(libraries, hooks);
288  libraries.verifyLibraries(hooks->getPosition());
289  }
290 
291  // Attempt to create the new client config. This ought to fly as
292  // we already validated everything.
293  D2ParamsPtr params(new D2Params(ip_address, port, dns_server_timeout,
294  ncr_protocol, ncr_format));
295 
296  ctx->getD2Params() = params;
297 
298  if (!check_only) {
299  // This occurs last as if it succeeds, there is no easy way
300  // revert it. As a result, the failure to commit a subsequent
301  // change causes problems when trying to roll back.
302  HooksManager::prepareUnloadLibraries();
303  static_cast<void>(HooksManager::unloadLibraries());
304  libraries.loadLibraries();
305  }
306 }
307 
308 }
309 }
boost::shared_ptr< D2Params > D2ParamsPtr
Defines a pointer for D2Params instances.
Definition: d2_config.h:256
Parser for hooks library list.
Definition: hooks_parser.h:21
const isc::hooks::HookLibsCollection & get() const
Provides access to the configured hooks libraries.
Definition: hooks_config.h:54
NameChangeProtocol stringToNcrProtocol(const std::string &protocol_str)
Function which converts text labels to NameChangeProtocol enums.
Definition: ncr_io.cc:23
DdnsDomainListMgrPtr parse(data::ConstElementPtr mgr_config, const std::string &mgr_name, const TSIGKeyInfoMapPtr keys)
Performs the actual parsing of the given manager element.
Definition: d2_config.cc:625
boost::shared_ptr< DdnsDomainListMgr > DdnsDomainListMgrPtr
Defines a pointer for DdnsDomain instances.
Definition: d2_cfg_mgr.h:153
std::vector< SimpleDefault > SimpleDefaults
This specifies all default values in a given scope (e.g. a subnet).
Parser for DdnsDomainListMgr.
Definition: d2_config.h:876
Exception thrown when the error during configuration handling occurs.
Definition: d2_config.h:135
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
Wrapper class that holds hooks libraries configuration.
Definition: hooks_config.h:36
NameChangeFormat
Defines the list of data wire formats supported.
Definition: ncr_msg.h:60
TSIGKeyInfoMapPtr parse(data::ConstElementPtr key_list_config)
Performs the parsing of the given list "tsig-key" elements.
Definition: d2_config.cc:457
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::string ncrProtocolToString(NameChangeProtocol protocol)
Function which converts NameChangeProtocol enums to text labels.
Definition: ncr_io.cc:36
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
boost::shared_ptr< D2CfgContext > D2CfgContextPtr
Pointer to a configuration context.
Definition: d2_cfg_mgr.h:23
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
void loadLibraries() const
Commits hooks libraries configuration.
Definition: hooks_config.cc:55
static isc::asiolink::IOAddress getAddress(const ConstElementPtr &scope, const std::string &name)
Returns a IOAddress parameter from a scope.
Defines the logger used by the top-level component of kea-dhcp-ddns.
std::string ncrFormatToString(NameChangeFormat format)
Function which converts NameChangeFormat enums to text labels.
Definition: ncr_msg.cc:35
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:66
NameChangeProtocol
Defines the list of socket protocols supported.
Definition: ncr_io.h:68
NameChangeFormat stringToNcrFormat(const std::string &fmt_str)
Function which converts labels to NameChangeFormat enum values.
Definition: ncr_msg.cc:26
Parser for a list of TSIGKeyInfos.
Definition: d2_config.h:769
A collection of classes for housing and parsing the application configuration necessary for the DHCP-...
void parse(HooksConfig &libraries, isc::data::ConstElementPtr value)
Parses parameters value.
Definition: hooks_parser.cc:28
void verifyLibraries(const isc::data::Element::Position &position) const
Verifies that libraries stored in libraries_ are valid.
Definition: hooks_config.cc:20
Acts as a storage vault for D2 global scalar parameters.
Definition: d2_config.h:142