Kea  2.1.7-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 <d2srv/d2_config.h>
10 #include <d2srv/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 milliseconds
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  { "key-name", Element::string, "" }
114 };
115 
117 
121 
122 size_t
123 D2SimpleParser::setAllDefaults(isc::data::ElementPtr global) {
124  size_t cnt = 0;
125  // Set global defaults first.
126  cnt = setDefaults(global, D2_GLOBAL_DEFAULTS);
127 
128  // If the key list is present, set its members' defaults
129  if (global->find("tsig-keys")) {
130  ConstElementPtr keys = global->get("tsig-keys");
131  cnt += setListDefaults(keys, TSIG_KEY_DEFAULTS);
132  } else {
133  // Not present, so add an empty list.
134  ConstElementPtr list(new ListElement());
135  global->set("tsig-keys", list);
136  cnt++;
137  }
138 
139  // Set the forward domain manager defaults.
140  cnt += setManagerDefaults(global, "forward-ddns", DDNS_DOMAIN_MGR_DEFAULTS);
141 
142  // Set the reverse domain manager defaults.
143  cnt += setManagerDefaults(global, "reverse-ddns", DDNS_DOMAIN_MGR_DEFAULTS);
144  return (cnt);
145 }
146 
147 size_t
148 D2SimpleParser::setDdnsDomainDefaults(ElementPtr domain,
149  const SimpleDefaults& domain_defaults) {
150  size_t cnt = 0;
151 
152  // Set the domain's scalar defaults
153  cnt += setDefaults(domain, domain_defaults);
154  if (domain->find("dns-servers")) {
155  // Now add the defaults to its server list.
156  ConstElementPtr servers = domain->get("dns-servers");
157  cnt += setListDefaults(servers, DNS_SERVER_DEFAULTS);
158  }
159 
160  return (cnt);
161 }
162 
163 
164 size_t
165 D2SimpleParser::setManagerDefaults(ElementPtr global,
166  const std::string& mgr_name,
167  const SimpleDefaults& mgr_defaults) {
168  size_t cnt = 0;
169 
170  if (!global->find(mgr_name)) {
171  // If it's not present, then default is an empty map
172  ConstElementPtr map(new MapElement());
173  global->set(mgr_name, map);
174  ++cnt;
175  } else {
176  // Get a writable copy of the manager element map
177  ElementPtr mgr =
178  boost::const_pointer_cast<Element>(global->get(mgr_name));
179 
180  // Set the manager's scalar defaults first
181  cnt += setDefaults(mgr, mgr_defaults);
182 
183  // Get the domain list and set defaults for them.
184  // The domain list may not be present ddns for this
185  // manager is disabled.
186  if (mgr->find("ddns-domains")) {
187  ConstElementPtr domains = mgr->get("ddns-domains");
188  BOOST_FOREACH(ElementPtr domain, domains->listValue()) {
189  // Set the domain's defaults. We can't use setListDefaults()
190  // as this does not handle sub-lists or maps, like server list.
191  cnt += setDdnsDomainDefaults(domain, DDNS_DOMAIN_DEFAULTS);
192  }
193  }
194 
195  }
196 
197  return (cnt);
198 }
199 
200 void D2SimpleParser::parse(const D2CfgContextPtr& ctx,
201  const isc::data::ConstElementPtr& config,
202  bool check_only) {
203  // TSIG keys need to parse before the Domains, so we can catch Domains
204  // that specify undefined keys. Create the necessary parsing order now.
205  // addToParseOrder("tsig-keys");
206  // addToParseOrder("forward-ddns");
207  // addToParseOrder("reverse-ddns");
208 
209  ConstElementPtr keys = config->get("tsig-keys");
210  if (keys) {
211  TSIGKeyInfoListParser parser;
212  ctx->setKeys(parser.parse(keys));
213  }
214 
215  ConstElementPtr fwd = config->get("forward-ddns");
216  if (fwd) {
218  DdnsDomainListMgrPtr mgr = parser.parse(fwd, "forward-ddns",
219  ctx->getKeys());
220  ctx->setForwardMgr(mgr);
221  }
222 
223  ConstElementPtr rev = config->get("reverse-ddns");
224  if (rev) {
226  DdnsDomainListMgrPtr mgr = parser.parse(rev, "reverse-ddns",
227  ctx->getKeys());
228  ctx->setReverseMgr(mgr);
229  }
230 
231  // Fetch the parameters in the config, performing any logical
232  // validation required.
233  asiolink::IOAddress ip_address(0);
234  uint32_t port = 0;
235  uint32_t dns_server_timeout = 0;
238 
239  ip_address = SimpleParser::getAddress(config, "ip-address");
240 
241  if ((ip_address.toText() == "0.0.0.0") ||
242  (ip_address.toText() == "::")) {
243  isc_throw(D2CfgError, "IP address cannot be \""
244  << ip_address << "\""
245  << " (" << config->get("ip-address")->getPosition() << ")");
246  }
247 
248  port = SimpleParser::getUint32(config, "port");
249 
250  dns_server_timeout = SimpleParser::getUint32(config, "dns-server-timeout");
251 
252  ncr_protocol = getProtocol(config, "ncr-protocol");
253  if (ncr_protocol != dhcp_ddns::NCR_UDP) {
254  isc_throw(D2CfgError, "ncr-protocol : "
255  << dhcp_ddns::ncrProtocolToString(ncr_protocol)
256  << " is not yet supported ("
257  << config->get("ncr-protocol")->getPosition() << ")");
258  }
259 
260  ncr_format = getFormat(config, "ncr-format");
261  if (ncr_format != dhcp_ddns::FMT_JSON) {
262  isc_throw(D2CfgError, "NCR Format:"
263  << dhcp_ddns::ncrFormatToString(ncr_format)
264  << " is not yet supported"
265  << " (" << config->get("ncr-format")->getPosition() << ")");
266  }
267 
268  ConstElementPtr user = config->get("user-context");
269  if (user) {
270  ctx->setContext(user);
271  }
272 
273  ConstElementPtr socket = config->get("control-socket");
274  if (socket) {
275  if (socket->getType() != Element::map) {
276  isc_throw(D2CfgError, "Specified control-socket is expected to be a map"
277  ", i.e. a structure defined within { }");
278  }
279  ctx->setControlSocketInfo(socket);
280  }
281 
282  // Finally, let's get the hook libs!
283  using namespace isc::hooks;
284  HooksConfig& libraries = ctx->getHooksConfig();
285  ConstElementPtr hooks = config->get("hooks-libraries");
286  if (hooks) {
287  HooksLibrariesParser hooks_parser;
288  hooks_parser.parse(libraries, hooks);
289  libraries.verifyLibraries(hooks->getPosition());
290  }
291 
292  // Attempt to create the new client config. This ought to fly as
293  // we already validated everything.
294  D2ParamsPtr params(new D2Params(ip_address, port, dns_server_timeout,
295  ncr_protocol, ncr_format));
296 
297  ctx->getD2Params() = params;
298 
299  if (!check_only) {
300  // This occurs last as if it succeeds, there is no easy way
301  // revert it. As a result, the failure to commit a subsequent
302  // change causes problems when trying to roll back.
303  HooksManager::prepareUnloadLibraries();
304  static_cast<void>(HooksManager::unloadLibraries());
305  libraries.loadLibraries();
306  }
307 }
308 
309 }
310 }
boost::shared_ptr< D2Params > D2ParamsPtr
Defines a pointer for D2Params instances.
Definition: d2_config.h:257
Parser for hooks library list.
Definition: hooks_parser.h:21
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:655
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:905
Exception thrown when the error during configuration handling occurs.
Definition: d2_config.h:136
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
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:463
#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:27
void verifyLibraries(const isc::data::Element::Position &position) const
Verifies that libraries stored in libraries_ are valid.
Definition: hooks_config.cc:20
boost::shared_ptr< D2CfgContext > D2CfgContextPtr
Pointer to a configuration context.
Definition: d2_cfg_mgr.h:23
void loadLibraries() const
Commits hooks libraries configuration.
Definition: hooks_config.cc:55
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
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-lfc.
const isc::hooks::HookLibsCollection & get() const
Provides access to the configured hooks libraries.
Definition: hooks_config.h:54
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:70
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:790
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
Acts as a storage vault for D2 global scalar parameters.
Definition: d2_config.h:143