Kea  1.9.9-git
dhcp6/json_config_parser.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-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 <asiolink/io_address.h>
10 #include <cc/data.h>
11 #include <cc/command_interpreter.h>
12 #include <config/command_mgr.h>
14 #include <dhcp/libdhcp++.h>
16 #include <dhcp6/dhcp6_log.h>
17 #include <dhcp6/dhcp6_srv.h>
18 #include <dhcp/iface_mgr.h>
19 #include <dhcpsrv/cb_ctl_dhcp4.h>
20 #include <dhcpsrv/cfg_option.h>
21 #include <dhcpsrv/cfgmgr.h>
22 #include <dhcpsrv/db_type.h>
23 #include <dhcpsrv/pool.h>
24 #include <dhcpsrv/subnet.h>
25 #include <dhcpsrv/timer_mgr.h>
26 #include <dhcpsrv/triplet.h>
41 #include <hooks/hooks_parser.h>
42 #include <hooks/hooks_manager.h>
43 #include <log/logger_support.h>
45 
46 #include <util/encode/hex.h>
47 #include <util/strutil.h>
48 
49 #include <boost/algorithm/string.hpp>
50 #include <boost/foreach.hpp>
51 #include <boost/lexical_cast.hpp>
52 #include <boost/scoped_ptr.hpp>
53 #include <boost/shared_ptr.hpp>
54 
55 #include <iostream>
56 #include <limits>
57 #include <map>
58 #include <netinet/in.h>
59 #include <vector>
60 
61 #include <stdint.h>
62 
63 using namespace std;
64 using namespace isc;
65 using namespace isc::data;
66 using namespace isc::dhcp;
67 using namespace isc::asiolink;
68 using namespace isc::hooks;
69 using namespace isc::process;
70 
71 namespace {
72 
77 void dirExists(const string& dir_path) {
78  struct stat statbuf;
79  if (stat(dir_path.c_str(), &statbuf) < 0) {
80  isc_throw(BadValue, "Bad directory '" << dir_path
81  << "': " << strerror(errno));
82  }
83  if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
84  isc_throw(BadValue, "'" << dir_path << "' is not a directory");
85  }
86 }
87 
96 class RSOOListConfigParser : public isc::data::SimpleParser {
97 public:
98 
106  void parse(const SrvConfigPtr& cfg, const isc::data::ConstElementPtr& value) {
107  try {
108  BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
109  std::string option_str = source_elem->stringValue();
110  // This option can be either code (integer) or name. Let's try code first
111  int64_t code = 0;
112  try {
113  code = boost::lexical_cast<int64_t>(option_str);
114  // Protect against the negative value and too high value.
115  if (code < 0) {
116  isc_throw(BadValue, "invalid option code value specified '"
117  << option_str << "', the option code must be a"
118  " non-negative value");
119 
120  } else if (code > std::numeric_limits<uint16_t>::max()) {
121  isc_throw(BadValue, "invalid option code value specified '"
122  << option_str << "', the option code must not be"
123  " greater than '" << std::numeric_limits<uint16_t>::max()
124  << "'");
125  }
126 
127  } catch (const boost::bad_lexical_cast &) {
128  // Oh well, it's not a number
129  }
130 
131  if (!code) {
132  const OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP6_OPTION_SPACE,
133  option_str);
134  if (def) {
135  code = def->getCode();
136  } else {
137  isc_throw(BadValue, "unable to find option code for the "
138  " specified option name '" << option_str << "'"
139  " while parsing the list of enabled"
140  " relay-supplied-options");
141  }
142  }
143  cfg->getCfgRSOO()->enable(code);
144  }
145  } catch (const std::exception& ex) {
146  // Rethrow exception with the appended position of the parsed
147  // element.
148  isc_throw(DhcpConfigError, ex.what() << " (" << value->getPosition() << ")");
149  }
150  }
151 };
152 
161 class Dhcp6ConfigParser : public isc::data::SimpleParser {
162 public:
163 
178  void parse(const SrvConfigPtr& srv_config, const ConstElementPtr& global) {
179 
180  // Set the data directory for server id file.
181  if (global->contains("data-directory")) {
182  CfgMgr::instance().setDataDir(getString(global, "data-directory"),
183  false);
184  }
185 
186  // Set the probation period for decline handling.
187  uint32_t probation_period =
188  getUint32(global, "decline-probation-period");
189  srv_config->setDeclinePeriod(probation_period);
190 
191  // Set the DHCPv4-over-DHCPv6 interserver port.
192  uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
193  srv_config->setDhcp4o6Port(dhcp4o6_port);
194 
195  // Set the global user context.
196  ConstElementPtr user_context = global->get("user-context");
197  if (user_context) {
198  srv_config->setContext(user_context);
199  }
200 
201  // Set the server's logical name
202  std::string server_tag = getString(global, "server-tag");
203  srv_config->setServerTag(server_tag);
204  }
205 
217  void parseEarly(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
218  // Set ip-reservations-unique flag.
219  bool ip_reservations_unique = getBoolean(global, "ip-reservations-unique");
220  cfg->setIPReservationsUnique(ip_reservations_unique);
221  }
222 
229  void
230  copySubnets6(const CfgSubnets6Ptr& dest, const CfgSharedNetworks6Ptr& from) {
231 
232  if (!dest || !from) {
233  isc_throw(BadValue, "Unable to copy subnets: at least one pointer is null");
234  }
235 
236  const SharedNetwork6Collection* networks = from->getAll();
237  if (!networks) {
238  // Nothing to copy. Technically, it should return a pointer to empty
239  // container, but let's handle null pointer as well.
240  return;
241  }
242 
243  // Let's go through all the networks one by one
244  for (auto net = networks->begin(); net != networks->end(); ++net) {
245 
246  // For each network go through all the subnets in it.
247  const Subnet6Collection* subnets = (*net)->getAllSubnets();
248  if (!subnets) {
249  // Shared network without subnets it weird, but we decided to
250  // accept such configurations.
251  continue;
252  }
253 
254  // For each subnet, add it to a list of regular subnets.
255  for (auto subnet = subnets->begin(); subnet != subnets->end(); ++subnet) {
256  dest->add(*subnet);
257  }
258  }
259  }
260 
269  void
270  sanityChecks(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
271 
273  cfg->sanityChecksLifetime("preferred-lifetime");
274  cfg->sanityChecksLifetime("valid-lifetime");
275 
277  const SharedNetwork6Collection* networks = cfg->getCfgSharedNetworks6()->getAll();
278  if (networks) {
279  sharedNetworksSanityChecks(*networks, global->get("shared-networks"));
280  }
281  }
282 
289  void
290  sharedNetworksSanityChecks(const SharedNetwork6Collection& networks,
291  ConstElementPtr json) {
292 
294  if (!json) {
295  // No json? That means that the shared-networks was never specified
296  // in the config.
297  return;
298  }
299 
300  // Used for names uniqueness checks.
301  std::set<string> names;
302 
303  // Let's go through all the networks one by one
304  for (auto net = networks.begin(); net != networks.end(); ++net) {
305  string txt;
306 
307  // Let's check if all subnets have either the same interface
308  // or don't have the interface specified at all.
309  string iface = (*net)->getIface();
310 
311  const Subnet6Collection* subnets = (*net)->getAllSubnets();
312  if (subnets) {
313 
314  bool rapid_commit = false;
315 
316  // For each subnet, add it to a list of regular subnets.
317  for (auto subnet = subnets->begin(); subnet != subnets->end(); ++subnet) {
318 
319  // Rapid commit must either be enabled or disabled in all subnets
320  // in the shared network.
321  if (subnet == subnets->begin()) {
322  // If this is the first subnet, remember the value.
323  rapid_commit = (*subnet)->getRapidCommit();
324  } else {
325  // Ok, this is the second or following subnets. The value
326  // must match what was set in the first subnet.
327  if (rapid_commit != (*subnet)->getRapidCommit()) {
328  isc_throw(DhcpConfigError, "All subnets in a shared network "
329  "must have the same rapid-commit value. Subnet "
330  << (*subnet)->toText()
331  << " has specified rapid-commit "
332  << ( (*subnet)->getRapidCommit() ? "true" : "false")
333  << ", but earlier subnet in the same shared-network"
334  << " or the shared-network itself used rapid-commit "
335  << (rapid_commit ? "true" : "false"));
336  }
337  }
338 
339  if (iface.empty()) {
340  iface = (*subnet)->getIface();
341  continue;
342  }
343 
344  if ((*subnet)->getIface().empty()) {
345  continue;
346  }
347 
348  if ((*subnet)->getIface() != iface) {
349  isc_throw(DhcpConfigError, "Subnet " << (*subnet)->toText()
350  << " has specified interface " << (*subnet)->getIface()
351  << ", but earlier subnet in the same shared-network"
352  << " or the shared-network itself used " << iface);
353  }
354 
355  // Let's collect the subnets in case we later find out the
356  // subnet doesn't have a mandatory name.
357  txt += (*subnet)->toText() + " ";
358  }
359  }
360 
361  // Next, let's check name of the shared network.
362  if ((*net)->getName().empty()) {
363  isc_throw(DhcpConfigError, "Shared-network with subnets "
364  << txt << " is missing mandatory 'name' parameter");
365  }
366 
367  // Is it unique?
368  if (names.find((*net)->getName()) != names.end()) {
369  isc_throw(DhcpConfigError, "A shared-network with "
370  "name " << (*net)->getName() << " defined twice.");
371  }
372  names.insert((*net)->getName());
373 
374  }
375  }
376 };
377 
378 } // anonymous namespace
379 
380 namespace isc {
381 namespace dhcp {
382 
391  // Get new socket configuration.
392  ConstElementPtr sock_cfg =
393  CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
394 
395  // Get current socket configuration.
396  ConstElementPtr current_sock_cfg =
397  CfgMgr::instance().getCurrentCfg()->getControlSocketInfo();
398 
399  // Determine if the socket configuration has changed. It has if
400  // both old and new configuration is specified but respective
401  // data elements aren't equal.
402  bool sock_changed = (sock_cfg && current_sock_cfg &&
403  !sock_cfg->equals(*current_sock_cfg));
404 
405  // If the previous or new socket configuration doesn't exist or
406  // the new configuration differs from the old configuration we
407  // close the existing socket and open a new socket as appropriate.
408  // Note that closing an existing socket means the client will not
409  // receive the configuration result.
410  if (!sock_cfg || !current_sock_cfg || sock_changed) {
411  // Close the existing socket (if any).
413 
414  if (sock_cfg) {
415  // This will create a control socket and install the external
416  // socket in IfaceMgr. That socket will be monitored when
417  // Dhcp4Srv::receivePacket() calls IfaceMgr::receive4() and
418  // callback in CommandMgr will be called, if necessary.
420  }
421  }
422 }
423 
426  bool check_only) {
427  if (!config_set) {
429  string("Can't parse NULL config"));
430  return (answer);
431  }
432 
434  .arg(server.redactConfig(config_set)->str());
435 
436  // Before starting any subnet operations, let's reset the subnet-id counter,
437  // so newly recreated configuration starts with first subnet-id equal 1.
438  Subnet::resetSubnetID();
439 
440  // Close DHCP sockets and remove any existing timers.
441  if (!check_only) {
442  IfaceMgr::instance().closeSockets();
443  TimerMgr::instance()->unregisterTimers();
444  server.discardPackets();
445  server.getCBControl()->reset();
446  }
447 
448  // Revert any runtime option definitions configured so far and not committed.
449  LibDHCP::revertRuntimeOptionDefs();
450  // Let's set empty container in case a user hasn't specified any configuration
451  // for option definitions. This is equivalent to committing empty container.
452  LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
453 
454  // Print the list of known backends.
455  HostDataSourceFactory::printRegistered();
456 
457  // Answer will hold the result.
458  ConstElementPtr answer;
459  // Rollback informs whether error occurred and original data
460  // have to be restored to global storages.
461  bool rollback = false;
462  // Global parameter name in case of an error.
463  string parameter_name;
464  ElementPtr mutable_cfg;
465  SrvConfigPtr srv_config;
466  try {
467  // Get the staging configuration.
468  srv_config = CfgMgr::instance().getStagingCfg();
469 
470  // This is a way to convert ConstElementPtr to ElementPtr.
471  // We need a config that can be edited, because we will insert
472  // default values and will insert derived values as well.
473  mutable_cfg = boost::const_pointer_cast<Element>(config_set);
474 
475  // Relocate dhcp-ddns parameters that have moved to global scope.
476  // Rule is that a global value overrides the dhcp-ddns value, so
477  // we need to do this before we apply global defaults.
478  // Note this is done for backward compatibility.
479  srv_config->moveDdnsParams(mutable_cfg);
480 
481  // Move from reservation mode to new reservations flags.
482  // @todo add warning
483  BaseNetworkParser::moveReservationMode(mutable_cfg);
484 
485  // Set all default values if not specified by the user.
486  SimpleParser6::setAllDefaults(mutable_cfg);
487 
488  // And now derive (inherit) global parameters to subnets, if not specified.
489  SimpleParser6::deriveParameters(mutable_cfg);
490 
491  // In principle we could have the following code structured as a series
492  // of long if else if clauses. That would give a marginal performance
493  // boost, but would make the code less readable. We had serious issues
494  // with the parser code debugability, so I decided to keep it as a
495  // series of independent ifs.
496 
497  // This parser is used in several places.
498  Dhcp6ConfigParser global_parser;
499 
500  // Apply global options in the staging config, e.g. ip-reservations-unique
501  global_parser.parseEarly(srv_config, mutable_cfg);
502 
503  // Specific check for this global parameter.
504  ConstElementPtr data_directory = mutable_cfg->get("data-directory");
505  if (data_directory) {
506  parameter_name = "data-directory";
507  dirExists(data_directory->stringValue());
508  }
509 
510  // We need definitions first
511  ConstElementPtr option_defs = mutable_cfg->get("option-def");
512  if (option_defs) {
513  parameter_name = "option-def";
514  OptionDefListParser parser(AF_INET6);
515  CfgOptionDefPtr cfg_option_def = srv_config->getCfgOptionDef();
516  parser.parse(cfg_option_def, option_defs);
517  }
518 
519  ConstElementPtr option_datas = mutable_cfg->get("option-data");
520  if (option_datas) {
521  parameter_name = "option-data";
522  OptionDataListParser parser(AF_INET6);
523  CfgOptionPtr cfg_option = srv_config->getCfgOption();
524  parser.parse(cfg_option, option_datas);
525  }
526 
527  ConstElementPtr mac_sources = mutable_cfg->get("mac-sources");
528  if (mac_sources) {
529  parameter_name = "mac-sources";
531  CfgMACSource& mac_source = srv_config->getMACSources();
532  parser.parse(mac_source, mac_sources);
533  }
534 
535  ConstElementPtr control_socket = mutable_cfg->get("control-socket");
536  if (control_socket) {
537  parameter_name = "control-socket";
538  ControlSocketParser parser;
539  parser.parse(*srv_config, control_socket);
540  }
541 
542  ConstElementPtr multi_threading = mutable_cfg->get("multi-threading");
543  if (multi_threading) {
544  parameter_name = "multi-threading";
546  parser.parse(*srv_config, multi_threading);
547  }
548 
549  ConstElementPtr queue_control = mutable_cfg->get("dhcp-queue-control");
550  if (queue_control) {
551  parameter_name = "dhcp-queue-control";
552  DHCPQueueControlParser parser;
553  srv_config->setDHCPQueueControl(parser.parse(queue_control));
554  }
555 
556  ConstElementPtr hr_identifiers =
557  mutable_cfg->get("host-reservation-identifiers");
558  if (hr_identifiers) {
559  parameter_name = "host-reservation-identifiers";
561  parser.parse(hr_identifiers);
562  }
563 
564  ConstElementPtr server_id = mutable_cfg->get("server-id");
565  if (server_id) {
566  parameter_name = "server-id";
567  DUIDConfigParser parser;
568  const CfgDUIDPtr& cfg = srv_config->getCfgDUID();
569  parser.parse(cfg, server_id);
570  }
571 
572  ConstElementPtr ifaces_config = mutable_cfg->get("interfaces-config");
573  if (ifaces_config) {
574  parameter_name = "interfaces-config";
575  IfacesConfigParser parser(AF_INET6, check_only);
576  CfgIfacePtr cfg_iface = srv_config->getCfgIface();
577  parser.parse(cfg_iface, ifaces_config);
578  }
579 
580  ConstElementPtr sanity_checks = mutable_cfg->get("sanity-checks");
581  if (sanity_checks) {
582  parameter_name = "sanity-checks";
583  SanityChecksParser parser;
584  parser.parse(*srv_config, sanity_checks);
585  }
586 
587  ConstElementPtr expiration_cfg =
588  mutable_cfg->get("expired-leases-processing");
589  if (expiration_cfg) {
590  parameter_name = "expired-leases-processing";
591  ExpirationConfigParser parser;
592  parser.parse(expiration_cfg);
593  }
594 
595  // The hooks-libraries configuration must be parsed after parsing
596  // multi-threading configuration so that libraries are checked
597  // for multi-threading compatibility.
598  ConstElementPtr hooks_libraries = mutable_cfg->get("hooks-libraries");
599  if (hooks_libraries) {
600  parameter_name = "hooks-libraries";
601  HooksLibrariesParser hooks_parser;
602  HooksConfig& libraries = srv_config->getHooksConfig();
603  hooks_parser.parse(libraries, hooks_libraries);
604  libraries.verifyLibraries(hooks_libraries->getPosition());
605  }
606 
607  // D2 client configuration.
608  D2ClientConfigPtr d2_client_cfg;
609 
610  // Legacy DhcpConfigParser stuff below.
611  ConstElementPtr dhcp_ddns = mutable_cfg->get("dhcp-ddns");
612  if (dhcp_ddns) {
613  parameter_name = "dhcp-ddns";
614  // Apply defaults
615  D2ClientConfigParser::setAllDefaults(dhcp_ddns);
616  D2ClientConfigParser parser;
617  d2_client_cfg = parser.parse(dhcp_ddns);
618  }
619 
620  ConstElementPtr client_classes = mutable_cfg->get("client-classes");
621  if (client_classes) {
622  parameter_name = "client-classes";
624  ClientClassDictionaryPtr dictionary =
625  parser.parse(client_classes, AF_INET6);
626  srv_config->setClientClassDictionary(dictionary);
627  }
628 
629  // Please move at the end when migration will be finished.
630  ConstElementPtr lease_database = mutable_cfg->get("lease-database");
631  if (lease_database) {
632  parameter_name = "lease-database";
633  db::DbAccessParser parser;
634  std::string access_string;
635  parser.parse(access_string, lease_database);
636  CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
637  cfg_db_access->setLeaseDbAccessString(access_string);
638  }
639 
640  ConstElementPtr hosts_database = mutable_cfg->get("hosts-database");
641  if (hosts_database) {
642  parameter_name = "hosts-database";
643  db::DbAccessParser parser;
644  std::string access_string;
645  parser.parse(access_string, hosts_database);
646  CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
647  cfg_db_access->setHostDbAccessString(access_string);
648  }
649 
650  ConstElementPtr hosts_databases = mutable_cfg->get("hosts-databases");
651  if (hosts_databases) {
652  parameter_name = "hosts-databases";
653  CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
654  db::DbAccessParser parser;
655  for (auto it : hosts_databases->listValue()) {
656  std::string access_string;
657  parser.parse(access_string, it);
658  cfg_db_access->setHostDbAccessString(access_string);
659  }
660  }
661 
662  // Keep relative orders of shared networks and subnets.
663  ConstElementPtr shared_networks = mutable_cfg->get("shared-networks");
664  if (shared_networks) {
665  parameter_name = "shared-networks";
672  CfgSharedNetworks6Ptr cfg = srv_config->getCfgSharedNetworks6();
673  parser.parse(cfg, shared_networks);
674 
675  // We also need to put the subnets it contains into normal
676  // subnets list.
677  global_parser.copySubnets6(srv_config->getCfgSubnets6(), cfg);
678  }
679 
680  ConstElementPtr subnet6 = mutable_cfg->get("subnet6");
681  if (subnet6) {
682  parameter_name = "subnet6";
683  Subnets6ListConfigParser subnets_parser;
684  // parse() returns number of subnets parsed. We may log it one day.
685  subnets_parser.parse(srv_config, subnet6);
686  }
687 
688  ConstElementPtr reservations = mutable_cfg->get("reservations");
689  if (reservations) {
690  parameter_name = "reservations";
691  HostCollection hosts;
693  parser.parse(SUBNET_ID_GLOBAL, reservations, hosts);
694  for (auto h = hosts.begin(); h != hosts.end(); ++h) {
695  srv_config->getCfgHosts()->add(*h);
696  }
697  }
698 
699  ConstElementPtr config_control = mutable_cfg->get("config-control");
700  if (config_control) {
701  parameter_name = "config-control";
702  ConfigControlParser parser;
703  ConfigControlInfoPtr config_ctl_info = parser.parse(config_control);
704  CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
705  }
706 
707  ConstElementPtr rsoo_list = mutable_cfg->get("relay-supplied-options");
708  if (rsoo_list) {
709  parameter_name = "relay-supplied-options";
710  RSOOListConfigParser parser;
711  parser.parse(srv_config, rsoo_list);
712  }
713 
714  ConstElementPtr compatibility = mutable_cfg->get("compatibility");
715  if (compatibility) {
716  for (auto kv : compatibility->mapValue()) {
717  if (kv.first == "lenient-option-parsing") {
718  CfgMgr::instance().getStagingCfg()->setLenientOptionParsing(
719  kv.second->boolValue());
720  }
721  }
722  }
723 
724  // Make parsers grouping.
725  ConfigPair config_pair;
726  const std::map<std::string, ConstElementPtr>& values_map =
727  mutable_cfg->mapValue();
728 
729  BOOST_FOREACH(config_pair, values_map) {
730 
731  parameter_name = config_pair.first;
732 
733  // These are converted to SimpleParser and are handled already above.
734  if ((config_pair.first == "data-directory") ||
735  (config_pair.first == "option-def") ||
736  (config_pair.first == "option-data") ||
737  (config_pair.first == "mac-sources") ||
738  (config_pair.first == "control-socket") ||
739  (config_pair.first == "multi-threading") ||
740  (config_pair.first == "dhcp-queue-control") ||
741  (config_pair.first == "host-reservation-identifiers") ||
742  (config_pair.first == "server-id") ||
743  (config_pair.first == "interfaces-config") ||
744  (config_pair.first == "sanity-checks") ||
745  (config_pair.first == "expired-leases-processing") ||
746  (config_pair.first == "hooks-libraries") ||
747  (config_pair.first == "dhcp-ddns") ||
748  (config_pair.first == "client-classes") ||
749  (config_pair.first == "lease-database") ||
750  (config_pair.first == "hosts-database") ||
751  (config_pair.first == "hosts-databases") ||
752  (config_pair.first == "subnet6") ||
753  (config_pair.first == "shared-networks") ||
754  (config_pair.first == "reservations") ||
755  (config_pair.first == "config-control") ||
756  (config_pair.first == "relay-supplied-options") ||
757  (config_pair.first == "compatibility")) {
758  continue;
759  }
760 
761  // As of Kea 1.6.0 we have two ways of inheriting the global parameters.
762  // The old method is used in JSON configuration parsers when the global
763  // parameters are derived into the subnets and shared networks and are
764  // being treated as explicitly specified. The new way used by the config
765  // backend is the dynamic inheritance whereby each subnet and shared
766  // network uses a callback function to return global parameter if it
767  // is not specified at lower level. This callback uses configured globals.
768  // We deliberately include both default and explicitly specified globals
769  // so as the callback can access the appropriate global values regardless
770  // whether they are set to a default or other value.
771  if ( (config_pair.first == "renew-timer") ||
772  (config_pair.first == "rebind-timer") ||
773  (config_pair.first == "preferred-lifetime") ||
774  (config_pair.first == "min-preferred-lifetime") ||
775  (config_pair.first == "max-preferred-lifetime") ||
776  (config_pair.first == "valid-lifetime") ||
777  (config_pair.first == "min-valid-lifetime") ||
778  (config_pair.first == "max-valid-lifetime") ||
779  (config_pair.first == "decline-probation-period") ||
780  (config_pair.first == "dhcp4o6-port") ||
781  (config_pair.first == "server-tag") ||
782  (config_pair.first == "reservation-mode") ||
783  (config_pair.first == "reservations-global") ||
784  (config_pair.first == "reservations-in-subnet") ||
785  (config_pair.first == "reservations-out-of-pool") ||
786  (config_pair.first == "calculate-tee-times") ||
787  (config_pair.first == "t1-percent") ||
788  (config_pair.first == "t2-percent") ||
789  (config_pair.first == "cache-threshold") ||
790  (config_pair.first == "cache-max-age") ||
791  (config_pair.first == "loggers") ||
792  (config_pair.first == "hostname-char-set") ||
793  (config_pair.first == "hostname-char-replacement") ||
794  (config_pair.first == "ddns-send-updates") ||
795  (config_pair.first == "ddns-override-no-update") ||
796  (config_pair.first == "ddns-override-client-update") ||
797  (config_pair.first == "ddns-replace-client-name") ||
798  (config_pair.first == "ddns-generated-prefix") ||
799  (config_pair.first == "ddns-qualifying-suffix") ||
800  (config_pair.first == "ddns-update-on-renew") ||
801  (config_pair.first == "ddns-use-conflict-resolution") ||
802  (config_pair.first == "store-extended-info") ||
803  (config_pair.first == "statistic-default-sample-count") ||
804  (config_pair.first == "statistic-default-sample-age") ||
805  (config_pair.first == "ip-reservations-unique")) {
806  CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
807  config_pair.second);
808  continue;
809  }
810 
811  // Nothing to configure for the user-context.
812  if (config_pair.first == "user-context") {
813  continue;
814  }
815 
816  // If we got here, no code handled this parameter, so we bail out.
818  "unsupported global configuration parameter: " << config_pair.first
819  << " (" << config_pair.second->getPosition() << ")");
820  }
821 
822  // Reset parameter name.
823  parameter_name = "<post parsing>";
824 
825  // Apply global options in the staging config.
826  global_parser.parse(srv_config, mutable_cfg);
827 
828  // This method conducts final sanity checks and tweaks. In particular,
829  // it checks that there is no conflict between plain subnets and those
830  // defined as part of shared networks.
831  global_parser.sanityChecks(srv_config, mutable_cfg);
832 
833  // Validate D2 client configuration.
834  if (!d2_client_cfg) {
835  d2_client_cfg.reset(new D2ClientConfig());
836  }
837  d2_client_cfg->validateContents();
838  srv_config->setD2ClientConfig(d2_client_cfg);
839  } catch (const isc::Exception& ex) {
841  .arg(parameter_name).arg(ex.what());
842  answer = isc::config::createAnswer(1, ex.what());
843 
844  // An error occurred, so make sure that we restore original data.
845  rollback = true;
846  } catch (...) {
847  // For things like bad_cast in boost::lexical_cast
848  LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(parameter_name);
849  answer = isc::config::createAnswer(1, "undefined configuration"
850  " processing error");
851 
852  // An error occurred, so make sure that we restore original data.
853  rollback = true;
854  }
855 
856  if (check_only) {
857  rollback = true;
858  if (!answer) {
859  answer = isc::config::createAnswer(0,
860  "Configuration seems sane. Control-socket, hook-libraries, and D2 "
861  "configuration were sanity checked, but not applied.");
862  }
863  }
864 
865  // So far so good, there was no parsing error so let's commit the
866  // configuration. This will add created subnets and option values into
867  // the server's configuration.
868  // This operation should be exception safe but let's make sure.
869  if (!rollback) {
870  try {
871 
872  // Setup the command channel.
874 
875  // No need to commit interface names as this is handled by the
876  // CfgMgr::commit() function.
877 
878  // Apply the staged D2ClientConfig, used to be done by parser commit
879  D2ClientConfigPtr cfg;
880  cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
881  CfgMgr::instance().setD2ClientConfig(cfg);
882 
883  // This occurs last as if it succeeds, there is no easy way to
884  // revert it. As a result, the failure to commit a subsequent
885  // change causes problems when trying to roll back.
886  HooksManager::prepareUnloadLibraries();
887  static_cast<void>(HooksManager::unloadLibraries());
888  const HooksConfig& libraries =
889  CfgMgr::instance().getStagingCfg()->getHooksConfig();
890  libraries.loadLibraries();
891  }
892  catch (const isc::Exception& ex) {
894  answer = isc::config::createAnswer(2, ex.what());
895 
896  // An error occurred, so make sure to restore the original data.
897  rollback = true;
898  } catch (...) {
899  // For things like bad_cast in boost::lexical_cast
901  answer = isc::config::createAnswer(2, "undefined configuration"
902  " parsing error");
903 
904  // An error occurred, so make sure to restore the original data.
905  rollback = true;
906  }
907  }
908 
909  // Moved from the commit block to add the config backend indication.
910  if (!rollback) {
911  try {
912 
913  // If there are config backends, fetch and merge into staging config
914  server.getCBControl()->databaseConfigFetch(srv_config,
915  CBControlDHCPv6::FetchMode::FETCH_ALL);
916  }
917  catch (const isc::Exception& ex) {
918  std::ostringstream err;
919  err << "during update from config backend database: " << ex.what();
921  answer = isc::config::createAnswer(2, err.str());
922 
923  // An error occurred, so make sure to restore the original data.
924  rollback = true;
925  } catch (...) {
926  // For things like bad_cast in boost::lexical_cast
927  std::ostringstream err;
928  err << "during update from config backend database: "
929  << "undefined configuration parsing error";
931  answer = isc::config::createAnswer(2, err.str());
932 
933  // An error occurred, so make sure to restore the original data.
934  rollback = true;
935  }
936  }
937 
938  // Rollback changes as the configuration parsing failed.
939  if (rollback) {
940  // Revert to original configuration of runtime option definitions
941  // in the libdhcp++.
942  LibDHCP::revertRuntimeOptionDefs();
943  return (answer);
944  }
945 
947  .arg(CfgMgr::instance().getStagingCfg()->
948  getConfigSummary(SrvConfig::CFGSEL_ALL6));
949 
950  // Everything was fine. Configuration is successful.
951  answer = isc::config::createAnswer(0, "Configuration successful.");
952  return (answer);
953 }
954 
955 } // namespace dhcp
956 } // namespace isc
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:174
boost::shared_ptr< CfgSharedNetworks6 > CfgSharedNetworks6Ptr
Pointer to the configuration of IPv6 shared networks.
void parse(const CfgOptionPtr &cfg, isc::data::ConstElementPtr option_data_list)
Parses a list of options, instantiates them and stores in cfg.
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
this class parses a list of DHCP6 subnets
Definition: dhcp_parsers.h:793
void parse(const CfgDUIDPtr &cfg, isc::data::ConstElementPtr duid_configuration)
Parses DUID configuration.
Parse Database Parameters.
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configures DHCPv6 server.
ClientClassDictionaryPtr parse(isc::data::ConstElementPtr class_def_list, uint16_t family)
Parse configuration entries.
#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 isc::log::MessageID DHCP6_CONFIG_START
Parser for a list of host identifiers for DHCPv6.
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:1036
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
STL namespace.
boost::shared_ptr< CfgIface > CfgIfacePtr
A pointer to the CfgIface .
Definition: cfg_iface.h:387
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".
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
Parser for D2ClientConfig.
Definition: dhcp_parsers.h:832
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.
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.
parser for MAC/hardware acquisition sources
Definition: dhcp_parsers.h:194
#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...
Parser for server DUID configuration.
Parsers for client class definitions.
Implements parser for config control information, "config-control".
Wrapper class that holds MAC/hardware address sources.
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
const int DBG_DHCP6_COMMAND
Debug level used to log receiving commands.
Definition: dhcp6_log.h:27
To be removed. Please use ConfigError instead.
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:56
void closeCommandSocket()
Shuts down any open control sockets.
Definition: command_mgr.cc:626
boost::shared_ptr< ClientClassDictionary > ClientClassDictionaryPtr
Defines a pointer to a ClientClassDictionary.
Parser for a list of shared networks.
const isc::log::MessageID DHCP6_PARSER_COMMIT_FAIL
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
Parser for option data values within a subnet.
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
Definition: cfg_subnets6.h:330
Parser for a list of option definitions.
Definition: dhcp_parsers.h:253
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:257
void parse(CfgMACSource &mac_sources, isc::data::ConstElementPtr value)
parses parameters value
Definition: dhcp_parsers.cc:45
void parse(const CfgIfacePtr &config, const isc::data::ConstElementPtr &values)
Parses content of the "interfaces-config".
Simple parser for sanity-checks structure.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void discardPackets()
Discards parked packets Clears the packet parking lots of all packets.
Definition: dhcp6_srv.cc:4259
void configureCommandChannel()
Initialize the command channel based on the staging configuration.
boost::multi_index_container< SharedNetwork6Ptr, 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< SharedNetwork6, std::string,&SharedNetwork6::getName > >, 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 > > >> SharedNetwork6Collection
Multi index container holding shared networks.
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list)
parses contents of the list
boost::multi_index_container< Subnet6Ptr, 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 > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime,&data::BaseStampedElement::getModificationTime > > >> Subnet6Collection
A collection of Subnet6 objects.
Definition: subnet.h:914
ConfigControlInfoPtr parse(const data::ConstElementPtr &config_control)
Parses a configuration control Element.
void loadLibraries() const
Commits hooks libraries configuration.
Definition: hooks_config.cc:55
const isc::log::MessageID DHCP6_CONFIG_COMPLETE
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:622
Defines the logger used by the top-level component of kea-dhcp-ddns.
CBControlDHCPv6Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp6_srv.h:124
void parse(SrvConfig &srv_cfg, isc::data::ConstElementPtr value)
"Parses" control-socket structure
Definition: dhcp_parsers.cc:76
Logging initialization functions.
This file contains several functions and constants that are used for handling commands and responses ...
#define DHCP6_OPTION_SPACE
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:66
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
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.
Parser for the control-socket structure.
Definition: dhcp_parsers.h:210
boost::shared_ptr< CfgDUID > CfgDUIDPtr
Pointer to the Non-const object.
Definition: cfg_duid.h:161
const isc::log::MessageID DHCP6_PARSER_COMMIT_EXCEPTION
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
boost::shared_ptr< ConfigControlInfo > ConfigControlInfoPtr
Defines a pointer to a ConfigControlInfo.
const isc::log::MessageID DHCP6_PARSER_FAIL
Simple parser for multi-threading structure.
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.
DHCPv6 server service.
Definition: dhcp6_srv.h:66
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:87
void verifyLibraries(const isc::data::Element::Position &position) const
Verifies that libraries stored in libraries_ are valid.
Definition: hooks_config.cc:20
static CommandMgr & instance()
CommandMgr is a singleton class.
Definition: command_mgr.cc:649
const isc::log::MessageID DHCP6_PARSER_EXCEPTION