Kea  2.1.7-git
dhcp4/json_config_parser.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2022 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 
10 #include <config/command_mgr.h>
14 #include <dhcp4/dhcp4_log.h>
15 #include <dhcp4/dhcp4_srv.h>
17 #include <dhcp/libdhcp++.h>
18 #include <dhcp/option_definition.h>
19 #include <dhcpsrv/cb_ctl_dhcp4.h>
20 #include <dhcpsrv/cfg_option.h>
21 #include <dhcpsrv/cfgmgr.h>
23 #include <dhcpsrv/db_type.h>
37 #include <dhcpsrv/timer_mgr.h>
38 #include <hooks/hooks_manager.h>
39 #include <hooks/hooks_parser.h>
41 #include <util/encode/hex.h>
43 #include <util/strutil.h>
44 
45 #include <boost/algorithm/string.hpp>
46 #include <boost/foreach.hpp>
47 #include <boost/lexical_cast.hpp>
48 
49 #include <iomanip>
50 #include <iostream>
51 #include <limits>
52 #include <map>
53 #include <netinet/in.h>
54 #include <vector>
55 
56 using namespace std;
57 using namespace isc;
58 using namespace isc::data;
59 using namespace isc::dhcp;
60 using namespace isc::asiolink;
61 using namespace isc::hooks;
62 using namespace isc::process;
63 using namespace isc::config;
64 using namespace isc::util;
65 
66 namespace {
67 
76 class Dhcp4ConfigParser : public isc::data::SimpleParser {
77 public:
78 
93  void parse(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
94 
95  // Set whether v4 server is supposed to echo back client-id
96  // (yes = RFC6842 compatible, no = backward compatibility)
97  bool echo_client_id = getBoolean(global, "echo-client-id");
98  cfg->setEchoClientId(echo_client_id);
99 
100  // Set the probation period for decline handling.
101  uint32_t probation_period =
102  getUint32(global, "decline-probation-period");
103  cfg->setDeclinePeriod(probation_period);
104 
105  // Set the DHCPv4-over-DHCPv6 interserver port.
106  uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
107  cfg->setDhcp4o6Port(dhcp4o6_port);
108 
109  // Set the global user context.
110  ConstElementPtr user_context = global->get("user-context");
111  if (user_context) {
112  cfg->setContext(user_context);
113  }
114 
115  // Set the server's logical name
116  std::string server_tag = getString(global, "server-tag");
117  cfg->setServerTag(server_tag);
118  }
119 
131  void parseEarly(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
132  // Set ip-reservations-unique flag.
133  bool ip_reservations_unique = getBoolean(global, "ip-reservations-unique");
134  cfg->setIPReservationsUnique(ip_reservations_unique);
135  }
136 
143  void
144  copySubnets4(const CfgSubnets4Ptr& dest, const CfgSharedNetworks4Ptr& from) {
145 
146  if (!dest || !from) {
147  isc_throw(BadValue, "Unable to copy subnets: at least one pointer is null");
148  }
149 
150  const SharedNetwork4Collection* networks = from->getAll();
151  if (!networks) {
152  // Nothing to copy. Technically, it should return a pointer to empty
153  // container, but let's handle null pointer as well.
154  return;
155  }
156 
157  // Let's go through all the networks one by one
158  for (auto net = networks->begin(); net != networks->end(); ++net) {
159 
160  // For each network go through all the subnets in it.
161  const Subnet4SimpleCollection* subnets = (*net)->getAllSubnets();
162  if (!subnets) {
163  // Shared network without subnets it weird, but we decided to
164  // accept such configurations.
165  continue;
166  }
167 
168  // For each subnet, add it to a list of regular subnets.
169  for (auto subnet = subnets->begin(); subnet != subnets->end(); ++subnet) {
170  dest->add(*subnet);
171  }
172  }
173  }
174 
183  void
184  sanityChecks(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
185 
187  cfg->sanityChecksLifetime("valid-lifetime");
188 
190  const SharedNetwork4Collection* networks = cfg->getCfgSharedNetworks4()->getAll();
191  if (networks) {
192  sharedNetworksSanityChecks(*networks, global->get("shared-networks"));
193  }
194  }
195 
202  void
203  sharedNetworksSanityChecks(const SharedNetwork4Collection& networks,
204  ConstElementPtr json) {
205 
207  if (!json) {
208  // No json? That means that the shared-networks was never specified
209  // in the config.
210  return;
211  }
212 
213  // Used for names uniqueness checks.
214  std::set<string> names;
215 
216  // Let's go through all the networks one by one
217  for (auto net = networks.begin(); net != networks.end(); ++net) {
218  string txt;
219 
220  // Let's check if all subnets have either the same interface
221  // or don't have the interface specified at all.
222  bool authoritative = (*net)->getAuthoritative();
223  string iface = (*net)->getIface();
224 
225  const Subnet4SimpleCollection* subnets = (*net)->getAllSubnets();
226  if (subnets) {
227  // For each subnet, add it to a list of regular subnets.
228  for (auto subnet = subnets->begin(); subnet != subnets->end(); ++subnet) {
229  if ((*subnet)->getAuthoritative() != authoritative) {
230  isc_throw(DhcpConfigError, "Subnet " << boolalpha
231  << (*subnet)->toText()
232  << " has different authoritative setting "
233  << (*subnet)->getAuthoritative()
234  << " than the shared-network itself: "
235  << authoritative);
236  }
237 
238  if (iface.empty()) {
239  iface = (*subnet)->getIface();
240  continue;
241  }
242 
243  if ((*subnet)->getIface().empty()) {
244  continue;
245  }
246 
247  if ((*subnet)->getIface() != iface) {
248  isc_throw(DhcpConfigError, "Subnet " << (*subnet)->toText()
249  << " has specified interface " << (*subnet)->getIface()
250  << ", but earlier subnet in the same shared-network"
251  << " or the shared-network itself used " << iface);
252  }
253 
254  // Let's collect the subnets in case we later find out the
255  // subnet doesn't have a mandatory name.
256  txt += (*subnet)->toText() + " ";
257  }
258  }
259 
260  // Next, let's check name of the shared network.
261  if ((*net)->getName().empty()) {
262  isc_throw(DhcpConfigError, "Shared-network with subnets "
263  << txt << " is missing mandatory 'name' parameter");
264  }
265 
266  // Is it unique?
267  if (names.find((*net)->getName()) != names.end()) {
268  isc_throw(DhcpConfigError, "A shared-network with "
269  "name " << (*net)->getName() << " defined twice.");
270  }
271  names.insert((*net)->getName());
272 
273  }
274  }
275 };
276 
277 } // anonymous namespace
278 
279 namespace isc {
280 namespace dhcp {
281 
290  // Get new socket configuration.
291  ConstElementPtr sock_cfg =
292  CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
293 
294  // Get current socket configuration.
295  ConstElementPtr current_sock_cfg =
296  CfgMgr::instance().getCurrentCfg()->getControlSocketInfo();
297 
298  // Determine if the socket configuration has changed. It has if
299  // both old and new configuration is specified but respective
300  // data elements aren't equal.
301  bool sock_changed = (sock_cfg && current_sock_cfg &&
302  !sock_cfg->equals(*current_sock_cfg));
303 
304  // If the previous or new socket configuration doesn't exist or
305  // the new configuration differs from the old configuration we
306  // close the existing socket and open a new socket as appropriate.
307  // Note that closing an existing socket means the client will not
308  // receive the configuration result.
309  if (!sock_cfg || !current_sock_cfg || sock_changed) {
310  // Close the existing socket (if any).
312 
313  if (sock_cfg) {
314  // This will create a control socket and install the external
315  // socket in IfaceMgr. That socket will be monitored when
316  // Dhcp4Srv::receivePacket() calls IfaceMgr::receive4() and
317  // callback in CommandMgr will be called, if necessary.
319  }
320  }
321 }
322 
325  bool check_only) {
326  if (!config_set) {
328  string("Can't parse NULL config"));
329  return (answer);
330  }
331 
333  .arg(server.redactConfig(config_set)->str());
334 
335  // Before starting any subnet operations, let's reset the subnet-id counter,
336  // so newly recreated configuration starts with first subnet-id equal 1.
337  Subnet::resetSubnetID();
338 
339  // Close DHCP sockets and remove any existing timers.
340  if (!check_only) {
341  IfaceMgr::instance().closeSockets();
342  TimerMgr::instance()->unregisterTimers();
343  server.discardPackets();
344  server.getCBControl()->reset();
345  }
346 
347  // Revert any runtime option definitions configured so far and not committed.
348  LibDHCP::revertRuntimeOptionDefs();
349  // Let's set empty container in case a user hasn't specified any configuration
350  // for option definitions. This is equivalent to committing empty container.
351  LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
352 
353  // Print the list of known backends.
354  HostDataSourceFactory::printRegistered();
355 
356  // Answer will hold the result.
357  ConstElementPtr answer;
358  // Rollback informs whether error occurred and original data
359  // have to be restored to global storages.
360  bool rollback = false;
361  // Global parameter name in case of an error.
362  string parameter_name;
363  ElementPtr mutable_cfg;
364  SrvConfigPtr srv_config;
365  try {
366  // Get the staging configuration.
367  srv_config = CfgMgr::instance().getStagingCfg();
368 
369  // This is a way to convert ConstElementPtr to ElementPtr.
370  // We need a config that can be edited, because we will insert
371  // default values and will insert derived values as well.
372  mutable_cfg = boost::const_pointer_cast<Element>(config_set);
373 
374  // Relocate dhcp-ddns parameters that have moved to global scope.
375  // Rule is that a global value overrides the dhcp-ddns value, so
376  // we need to do this before we apply global defaults.
377  // Note this is done for backward compatibility.
378  srv_config->moveDdnsParams(mutable_cfg);
379 
380  // Move from reservation mode to new reservations flags.
381  // @todo add warning
382  BaseNetworkParser::moveReservationMode(mutable_cfg);
383 
384  // Set all default values if not specified by the user.
385  SimpleParser4::setAllDefaults(mutable_cfg);
386 
387  // And now derive (inherit) global parameters to subnets, if not specified.
388  SimpleParser4::deriveParameters(mutable_cfg);
389 
390  // In principle we could have the following code structured as a series
391  // of long if else if clauses. That would give a marginal performance
392  // boost, but would make the code less readable. We had serious issues
393  // with the parser code debugability, so I decided to keep it as a
394  // series of independent ifs.
395 
396  // This parser is used in several places.
397  Dhcp4ConfigParser global_parser;
398 
399  // Apply global options in the staging config, e.g. ip-reservations-unique
400  global_parser.parseEarly(srv_config, mutable_cfg);
401 
402  // We need definitions first
403  ConstElementPtr option_defs = mutable_cfg->get("option-def");
404  if (option_defs) {
405  parameter_name = "option-def";
406  OptionDefListParser parser(AF_INET);
407  CfgOptionDefPtr cfg_option_def = srv_config->getCfgOptionDef();
408  parser.parse(cfg_option_def, option_defs);
409  }
410 
411  ConstElementPtr option_datas = mutable_cfg->get("option-data");
412  if (option_datas) {
413  parameter_name = "option-data";
414  OptionDataListParser parser(AF_INET);
415  CfgOptionPtr cfg_option = srv_config->getCfgOption();
416  parser.parse(cfg_option, option_datas);
417  }
418 
419  ConstElementPtr control_socket = mutable_cfg->get("control-socket");
420  if (control_socket) {
421  parameter_name = "control-socket";
422  ControlSocketParser parser;
423  parser.parse(*srv_config, control_socket);
424  }
425 
426  ConstElementPtr multi_threading = mutable_cfg->get("multi-threading");
427  if (multi_threading) {
428  parameter_name = "multi-threading";
430  parser.parse(*srv_config, multi_threading);
431  }
432 
434  ConstElementPtr queue_control = mutable_cfg->get("dhcp-queue-control");
435  if (queue_control) {
436  parameter_name = "dhcp-queue-control";
437  DHCPQueueControlParser parser;
438  srv_config->setDHCPQueueControl(parser.parse(queue_control));
439  }
440 
442  ConstElementPtr reservations_lookup_first = mutable_cfg->get("reservations-lookup-first");
443  if (reservations_lookup_first) {
444  parameter_name = "reservations-lookup-first";
445  if (MultiThreadingMgr::instance().getMode()) {
447  }
448  srv_config->setReservationsLookupFirst(reservations_lookup_first->boolValue());
449  }
450 
451  ConstElementPtr hr_identifiers =
452  mutable_cfg->get("host-reservation-identifiers");
453  if (hr_identifiers) {
454  parameter_name = "host-reservation-identifiers";
456  parser.parse(hr_identifiers);
457  }
458 
459  ConstElementPtr ifaces_config = mutable_cfg->get("interfaces-config");
460  if (ifaces_config) {
461  parameter_name = "interfaces-config";
462  IfacesConfigParser parser(AF_INET, check_only);
463  CfgIfacePtr cfg_iface = srv_config->getCfgIface();
464  parser.parse(cfg_iface, ifaces_config);
465  }
466 
467  ConstElementPtr sanity_checks = mutable_cfg->get("sanity-checks");
468  if (sanity_checks) {
469  parameter_name = "sanity-checks";
470  SanityChecksParser parser;
471  parser.parse(*srv_config, sanity_checks);
472  }
473 
474  ConstElementPtr expiration_cfg =
475  mutable_cfg->get("expired-leases-processing");
476  if (expiration_cfg) {
477  parameter_name = "expired-leases-processing";
478  ExpirationConfigParser parser;
479  parser.parse(expiration_cfg);
480  }
481 
482  // The hooks-libraries configuration must be parsed after parsing
483  // multi-threading configuration so that libraries are checked
484  // for multi-threading compatibility.
485  ConstElementPtr hooks_libraries = mutable_cfg->get("hooks-libraries");
486  if (hooks_libraries) {
487  parameter_name = "hooks-libraries";
488  HooksLibrariesParser hooks_parser;
489  HooksConfig& libraries = srv_config->getHooksConfig();
490  hooks_parser.parse(libraries, hooks_libraries);
491  libraries.verifyLibraries(hooks_libraries->getPosition());
492  }
493 
494  // D2 client configuration.
495  D2ClientConfigPtr d2_client_cfg;
496 
497  // Legacy DhcpConfigParser stuff below.
498  ConstElementPtr dhcp_ddns = mutable_cfg->get("dhcp-ddns");
499  if (dhcp_ddns) {
500  parameter_name = "dhcp-ddns";
501  // Apply defaults
502  D2ClientConfigParser::setAllDefaults(dhcp_ddns);
503  D2ClientConfigParser parser;
504  d2_client_cfg = parser.parse(dhcp_ddns);
505  }
506 
507  ConstElementPtr client_classes = mutable_cfg->get("client-classes");
508  if (client_classes) {
509  parameter_name = "client-classes";
511  ClientClassDictionaryPtr dictionary =
512  parser.parse(client_classes, AF_INET);
513  srv_config->setClientClassDictionary(dictionary);
514  }
515 
516  // Please move at the end when migration will be finished.
517  ConstElementPtr lease_database = mutable_cfg->get("lease-database");
518  if (lease_database) {
519  parameter_name = "lease-database";
520  db::DbAccessParser parser;
521  std::string access_string;
522  parser.parse(access_string, lease_database);
523  CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
524  cfg_db_access->setLeaseDbAccessString(access_string);
525  }
526 
527  ConstElementPtr hosts_database = mutable_cfg->get("hosts-database");
528  if (hosts_database) {
529  parameter_name = "hosts-database";
530  db::DbAccessParser parser;
531  std::string access_string;
532  parser.parse(access_string, hosts_database);
533  CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
534  cfg_db_access->setHostDbAccessString(access_string);
535  }
536 
537  ConstElementPtr hosts_databases = mutable_cfg->get("hosts-databases");
538  if (hosts_databases) {
539  parameter_name = "hosts-databases";
540  CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
541  db::DbAccessParser parser;
542  for (auto it : hosts_databases->listValue()) {
543  std::string access_string;
544  parser.parse(access_string, it);
545  cfg_db_access->setHostDbAccessString(access_string);
546  }
547  }
548 
549  // Keep relative orders of shared networks and subnets.
550  ConstElementPtr shared_networks = mutable_cfg->get("shared-networks");
551  if (shared_networks) {
552  parameter_name = "shared-networks";
559  CfgSharedNetworks4Ptr cfg = srv_config->getCfgSharedNetworks4();
560  parser.parse(cfg, shared_networks);
561 
562  // We also need to put the subnets it contains into normal
563  // subnets list.
564  global_parser.copySubnets4(srv_config->getCfgSubnets4(), cfg);
565  }
566 
567  ConstElementPtr subnet4 = mutable_cfg->get("subnet4");
568  if (subnet4) {
569  parameter_name = "subnet4";
570  Subnets4ListConfigParser subnets_parser;
571  // parse() returns number of subnets parsed. We may log it one day.
572  subnets_parser.parse(srv_config, subnet4);
573  }
574 
575  ConstElementPtr reservations = mutable_cfg->get("reservations");
576  if (reservations) {
577  parameter_name = "reservations";
578  HostCollection hosts;
580  parser.parse(SUBNET_ID_GLOBAL, reservations, hosts);
581  for (auto h = hosts.begin(); h != hosts.end(); ++h) {
582  srv_config->getCfgHosts()->add(*h);
583  }
584  }
585 
586  ConstElementPtr config_control = mutable_cfg->get("config-control");
587  if (config_control) {
588  parameter_name = "config-control";
589  ConfigControlParser parser;
590  ConfigControlInfoPtr config_ctl_info = parser.parse(config_control);
591  CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
592  }
593 
594  ConstElementPtr compatibility = mutable_cfg->get("compatibility");
595  if (compatibility) {
596  for (auto kv : compatibility->mapValue()) {
597  if (kv.first == "lenient-option-parsing") {
598  CfgMgr::instance().getStagingCfg()->setLenientOptionParsing(
599  kv.second->boolValue());
600  }
601  }
602  }
603 
604  // Make parsers grouping.
605  ConfigPair config_pair;
606  const std::map<std::string, ConstElementPtr>& values_map =
607  mutable_cfg->mapValue();
608 
609  BOOST_FOREACH(config_pair, values_map) {
610 
611  parameter_name = config_pair.first;
612 
613  // These are converted to SimpleParser and are handled already above.
614  if ((config_pair.first == "option-def") ||
615  (config_pair.first == "option-data") ||
616  (config_pair.first == "control-socket") ||
617  (config_pair.first == "multi-threading") ||
618  (config_pair.first == "dhcp-queue-control") ||
619  (config_pair.first == "host-reservation-identifiers") ||
620  (config_pair.first == "interfaces-config") ||
621  (config_pair.first == "sanity-checks") ||
622  (config_pair.first == "expired-leases-processing") ||
623  (config_pair.first == "hooks-libraries") ||
624  (config_pair.first == "dhcp-ddns") ||
625  (config_pair.first == "client-classes") ||
626  (config_pair.first == "lease-database") ||
627  (config_pair.first == "hosts-database") ||
628  (config_pair.first == "hosts-databases") ||
629  (config_pair.first == "subnet4") ||
630  (config_pair.first == "shared-networks") ||
631  (config_pair.first == "reservations") ||
632  (config_pair.first == "config-control") ||
633  (config_pair.first == "loggers") ||
634  (config_pair.first == "compatibility")) {
635  continue;
636  }
637 
638  // As of Kea 1.6.0 we have two ways of inheriting the global parameters.
639  // The old method is used in JSON configuration parsers when the global
640  // parameters are derived into the subnets and shared networks and are
641  // being treated as explicitly specified. The new way used by the config
642  // backend is the dynamic inheritance whereby each subnet and shared
643  // network uses a callback function to return global parameter if it
644  // is not specified at lower level. This callback uses configured globals.
645  // We deliberately include both default and explicitly specified globals
646  // so as the callback can access the appropriate global values regardless
647  // whether they are set to a default or other value.
648  if ( (config_pair.first == "renew-timer") ||
649  (config_pair.first == "rebind-timer") ||
650  (config_pair.first == "valid-lifetime") ||
651  (config_pair.first == "min-valid-lifetime") ||
652  (config_pair.first == "max-valid-lifetime") ||
653  (config_pair.first == "decline-probation-period") ||
654  (config_pair.first == "dhcp4o6-port") ||
655  (config_pair.first == "echo-client-id") ||
656  (config_pair.first == "match-client-id") ||
657  (config_pair.first == "authoritative") ||
658  (config_pair.first == "next-server") ||
659  (config_pair.first == "server-hostname") ||
660  (config_pair.first == "boot-file-name") ||
661  (config_pair.first == "server-tag") ||
662  (config_pair.first == "reservation-mode") ||
663  (config_pair.first == "reservations-global") ||
664  (config_pair.first == "reservations-in-subnet") ||
665  (config_pair.first == "reservations-out-of-pool") ||
666  (config_pair.first == "calculate-tee-times") ||
667  (config_pair.first == "t1-percent") ||
668  (config_pair.first == "t2-percent") ||
669  (config_pair.first == "cache-threshold") ||
670  (config_pair.first == "cache-max-age") ||
671  (config_pair.first == "hostname-char-set") ||
672  (config_pair.first == "hostname-char-replacement") ||
673  (config_pair.first == "ddns-send-updates") ||
674  (config_pair.first == "ddns-override-no-update") ||
675  (config_pair.first == "ddns-override-client-update") ||
676  (config_pair.first == "ddns-replace-client-name") ||
677  (config_pair.first == "ddns-generated-prefix") ||
678  (config_pair.first == "ddns-qualifying-suffix") ||
679  (config_pair.first == "ddns-update-on-renew") ||
680  (config_pair.first == "ddns-use-conflict-resolution") ||
681  (config_pair.first == "store-extended-info") ||
682  (config_pair.first == "statistic-default-sample-count") ||
683  (config_pair.first == "statistic-default-sample-age") ||
684  (config_pair.first == "early-global-reservations-lookup") ||
685  (config_pair.first == "ip-reservations-unique") ||
686  (config_pair.first == "reservations-lookup-first") ||
687  (config_pair.first == "parked-packet-limit")) {
688  CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
689  config_pair.second);
690  continue;
691  }
692 
693  // Nothing to configure for the user-context.
694  if (config_pair.first == "user-context") {
695  continue;
696  }
697 
698  // If we got here, no code handled this parameter, so we bail out.
700  "unsupported global configuration parameter: " << config_pair.first
701  << " (" << config_pair.second->getPosition() << ")");
702  }
703 
704  // Reset parameter name.
705  parameter_name = "<post parsing>";
706 
707  // Apply global options in the staging config.
708  global_parser.parse(srv_config, mutable_cfg);
709 
710  // This method conducts final sanity checks and tweaks. In particular,
711  // it checks that there is no conflict between plain subnets and those
712  // defined as part of shared networks.
713  global_parser.sanityChecks(srv_config, mutable_cfg);
714 
715  // Validate D2 client configuration.
716  if (!d2_client_cfg) {
717  d2_client_cfg.reset(new D2ClientConfig());
718  }
719  d2_client_cfg->validateContents();
720  srv_config->setD2ClientConfig(d2_client_cfg);
721  } catch (const isc::Exception& ex) {
723  .arg(parameter_name).arg(ex.what());
725 
726  // An error occurred, so make sure that we restore original data.
727  rollback = true;
728  } catch (...) {
729  // For things like bad_cast in boost::lexical_cast
730  LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(parameter_name);
731  answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
732  " processing error");
733 
734  // An error occurred, so make sure that we restore original data.
735  rollback = true;
736  }
737 
738  if (check_only) {
739  rollback = true;
740  if (!answer) {
742  "Configuration seems sane. Control-socket, hook-libraries, and D2 "
743  "configuration were sanity checked, but not applied.");
744  }
745  }
746 
747  // So far so good, there was no parsing error so let's commit the
748  // configuration. This will add created subnets and option values into
749  // the server's configuration.
750  // This operation should be exception safe but let's make sure.
751  if (!rollback) {
752  try {
753 
754  // Setup the command channel.
756 
757  // No need to commit interface names as this is handled by the
758  // CfgMgr::commit() function.
759 
760  // Apply the staged D2ClientConfig, used to be done by parser commit
761  D2ClientConfigPtr cfg;
762  cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
763  CfgMgr::instance().setD2ClientConfig(cfg);
764 
765  // This occurs last as if it succeeds, there is no easy way to
766  // revert it. As a result, the failure to commit a subsequent
767  // change causes problems when trying to roll back.
768  HooksManager::prepareUnloadLibraries();
769  static_cast<void>(HooksManager::unloadLibraries());
770  const HooksConfig& libraries =
771  CfgMgr::instance().getStagingCfg()->getHooksConfig();
772  libraries.loadLibraries();
773  } catch (const isc::Exception& ex) {
776 
777  // An error occurred, so make sure to restore the original data.
778  rollback = true;
779  } catch (...) {
780  // For things like bad_cast in boost::lexical_cast
782  answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
783  " parsing error");
784 
785  // An error occurred, so make sure to restore the original data.
786  rollback = true;
787  }
788  }
789 
790  // Moved from the commit block to add the config backend indication.
791  if (!rollback) {
792  try {
793 
794  // If there are config backends, fetch and merge into staging config
795  server.getCBControl()->databaseConfigFetch(srv_config,
796  CBControlDHCPv4::FetchMode::FETCH_ALL);
797  } catch (const isc::Exception& ex) {
798  std::ostringstream err;
799  err << "during update from config backend database: " << ex.what();
801  answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
802 
803  // An error occurred, so make sure to restore the original data.
804  rollback = true;
805  } catch (...) {
806  // For things like bad_cast in boost::lexical_cast
807  std::ostringstream err;
808  err << "during update from config backend database: "
809  << "undefined configuration parsing error";
811  answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
812 
813  // An error occurred, so make sure to restore the original data.
814  rollback = true;
815  }
816  }
817 
818  // Rollback changes as the configuration parsing failed.
819  if (rollback) {
820  // Revert to original configuration of runtime option definitions
821  // in the libdhcp++.
822  LibDHCP::revertRuntimeOptionDefs();
823  return (answer);
824  }
825 
827  .arg(CfgMgr::instance().getStagingCfg()->
828  getConfigSummary(SrvConfig::CFGSEL_ALL4));
829 
830  // Everything was fine. Configuration is successful.
831  answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Configuration successful.");
832  return (answer);
833 }
834 
835 } // namespace dhcp
836 } // namespace isc
DHCPv4 server service.
Definition: dhcp4_srv.h:253
void parse(isc::data::ConstElementPtr expiration_config)
Parses parameters in the JSON map, pertaining to the processing of the expired leases.
Parser for the configuration of DHCP packet queue controls.
std::pair< std::string, isc::data::ConstElementPtr > ConfigPair
Combination of parameter name and configuration contents.
Definition: dhcp_parsers.h:175
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
const isc::log::MessageID DHCP4_PARSER_EXCEPTION
void parse(const CfgOptionPtr &cfg, isc::data::ConstElementPtr option_data_list)
Parses a list of options, instantiates them and stores in cfg.
const isc::log::MessageID DHCP4_PARSER_COMMIT_FAIL
D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg)
Parses a given dhcp-ddns element into D2ClientConfig.
Parser for hooks library list.
Definition: hooks_parser.h:21
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:706
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list)
parses contents of the list
Parse Database Parameters.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
const isc::log::MessageID DHCP4_PARSER_COMMIT_EXCEPTION
const isc::log::MessageID DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED
Parser for the configuration parameters pertaining to the processing of expired leases.
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1165
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
STL namespace.
boost::shared_ptr< CfgIface > CfgIfacePtr
A pointer to the CfgIface .
Definition: cfg_iface.h:489
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:794
Wrapper class that holds hooks libraries configuration.
Definition: hooks_config.h:36
data::ElementPtr parse(const isc::data::ConstElementPtr &control_elem)
Parses content of the "dhcp-queue-control".
this class parses list of DHCP4 subnets
Definition: dhcp_parsers.h:641
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
void discardPackets()
Discards parked packets Clears the packet parking lots of all packets.
Definition: dhcp4_srv.cc:4311
boost::shared_ptr< CfgSubnets4 > CfgSubnets4Ptr
Non-const pointer.
Definition: cfg_subnets4.h:333
Parser for D2ClientConfig.
Definition: dhcp_parsers.h:981
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void parse(SrvConfig &srv_cfg, const isc::data::ConstElementPtr &value)
parses JSON structure.
Parser for the configuration of interfaces.
Class of option definition space container.
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
Definition: dhcp4_log.h:90
void parse(const SubnetID &subnet_id, isc::data::ConstElementPtr hr_list, HostCollection &hosts_list)
Parses a list of host reservation entries for a subnet.
void parse(isc::data::ConstElementPtr ids_list)
Parses a list of host identifiers.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
boost::shared_ptr< CfgSharedNetworks4 > CfgSharedNetworks4Ptr
Pointer to the configuration of IPv4 shared networks.
Definition: edns.h:19
Parsers for client class definitions.
Implements parser for config control information, "config-control".
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
To be removed. Please use ConfigError instead.
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:57
void closeCommandSocket()
Shuts down any open control sockets.
Definition: command_mgr.cc:627
boost::shared_ptr< ClientClassDictionary > ClientClassDictionaryPtr
Defines a pointer to a ClientClassDictionary.
boost::multi_index_container< Subnet4Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > > >> Subnet4SimpleCollection
A simple collection of Subnet4 objects.
Definition: subnet.h:837
Parser for a list of shared networks.
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
Parser for option data values within a subnet.
Parser for a list of option definitions.
Definition: dhcp_parsers.h:254
void loadLibraries() const
Commits hooks libraries configuration.
Definition: hooks_config.cc:55
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:257
void parse(const CfgIfacePtr &config, const isc::data::ConstElementPtr &values)
Parses content of the "interfaces-config".
Simple parser for sanity-checks structure.
void configureCommandChannel()
Initialize the command channel based on the staging configuration.
ConfigControlInfoPtr parse(const data::ConstElementPtr &config_control)
Parses a configuration control Element.
Parser for a list of host identifiers for DHCPv4.
This is a base class for exceptions thrown from the DNS library module.
void openCommandSocket(const isc::data::ConstElementPtr &socket_info)
Opens control socket with parameters specified in socket_info.
Definition: command_mgr.cc:623
Defines the logger used by the top-level component of kea-lfc.
void parse(SrvConfig &srv_cfg, isc::data::ConstElementPtr value)
"Parses" control-socket structure
Definition: dhcp_parsers.cc:76
boost::multi_index_container< SharedNetwork4Ptr, boost::multi_index::indexed_by< boost::multi_index::random_access< boost::multi_index::tag< SharedNetworkRandomAccessIndexTag > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< SharedNetworkIdIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, uint64_t, &data::BaseStampedElement::getId > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SharedNetworkNameIndexTag >, boost::multi_index::const_mem_fun< SharedNetwork4, std::string, &SharedNetwork4::getName > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SharedNetworkServerIdIndexTag >, boost::multi_index::const_mem_fun< Network4, asiolink::IOAddress, &Network4::getServerId > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SharedNetworkModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > >> SharedNetwork4Collection
Multi index container holding shared networks.
ClientClassDictionaryPtr parse(isc::data::ConstElementPtr class_def_list, uint16_t family, bool check_dependencies=true)
Parse configuration entries.
This file contains several functions and constants that are used for handling commands and responses ...
const isc::log::MessageID DHCP4_PARSER_FAIL
const isc::log::MessageID DHCP4_CONFIG_START
void parse(CfgSharedNetworksTypePtr &cfg, const data::ConstElementPtr &shared_networks_list_data)
Parses a list of shared networks.
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:70
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
Parser for a list of host reservations for a subnet.
void parse(SrvConfig &srv_cfg, const isc::data::ConstElementPtr &value)
parses JSON structure
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list)
Parses a list of option definitions, create them and store in cfg.
CBControlDHCPv4Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp4_srv.h:318
Parser for the control-socket structure.
Definition: dhcp_parsers.h:211
const int DBG_DHCP4_COMMAND
Debug level used to log receiving commands.
Definition: dhcp4_log.h:30
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
boost::shared_ptr< ConfigControlInfo > ConfigControlInfoPtr
Defines a pointer to a ConfigControlInfo.
Simple parser for multi-threading structure.
const isc::log::MessageID DHCP4_CONFIG_COMPLETE
void parse(std::string &access_string, isc::data::ConstElementPtr database_config)
Parse configuration value.
void parse(HooksConfig &libraries, isc::data::ConstElementPtr value)
Parses parameters value.
Definition: hooks_parser.cc:28
Parser for a list of client class definitions.
Contains declarations for loggers used by the DHCPv4 server component.
static CommandMgr & instance()
CommandMgr is a singleton class.
Definition: command_mgr.cc:650