Kea 2.0.1
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
10#include <cc/data.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>
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
63using namespace std;
64using namespace isc;
65using namespace isc::data;
66using namespace isc::dhcp;
67using namespace isc::asiolink;
68using namespace isc::hooks;
69using namespace isc::process;
70
71namespace {
72
77void 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
96class RSOOListConfigParser : public isc::data::SimpleParser {
97public:
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
161class Dhcp6ConfigParser : public isc::data::SimpleParser {
162public:
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
380namespace isc {
381namespace 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.
439
440 // Close DHCP sockets and remove any existing timers.
441 if (!check_only) {
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.
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.
453
454 // Print the list of known backends.
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
484
485 // Set all default values if not specified by the user.
487
488 // And now derive (inherit) global parameters to subnets, if not specified.
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";
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";
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
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 (config_pair.first == "parked-packet-limit")) {
807 CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
808 config_pair.second);
809 continue;
810 }
811
812 // Nothing to configure for the user-context.
813 if (config_pair.first == "user-context") {
814 continue;
815 }
816
817 // If we got here, no code handled this parameter, so we bail out.
819 "unsupported global configuration parameter: " << config_pair.first
820 << " (" << config_pair.second->getPosition() << ")");
821 }
822
823 // Reset parameter name.
824 parameter_name = "<post parsing>";
825
826 // Apply global options in the staging config.
827 global_parser.parse(srv_config, mutable_cfg);
828
829 // This method conducts final sanity checks and tweaks. In particular,
830 // it checks that there is no conflict between plain subnets and those
831 // defined as part of shared networks.
832 global_parser.sanityChecks(srv_config, mutable_cfg);
833
834 // Validate D2 client configuration.
835 if (!d2_client_cfg) {
836 d2_client_cfg.reset(new D2ClientConfig());
837 }
838 d2_client_cfg->validateContents();
839 srv_config->setD2ClientConfig(d2_client_cfg);
840 } catch (const isc::Exception& ex) {
842 .arg(parameter_name).arg(ex.what());
843 answer = isc::config::createAnswer(1, ex.what());
844
845 // An error occurred, so make sure that we restore original data.
846 rollback = true;
847 } catch (...) {
848 // For things like bad_cast in boost::lexical_cast
849 LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(parameter_name);
850 answer = isc::config::createAnswer(1, "undefined configuration"
851 " processing error");
852
853 // An error occurred, so make sure that we restore original data.
854 rollback = true;
855 }
856
857 if (check_only) {
858 rollback = true;
859 if (!answer) {
860 answer = isc::config::createAnswer(0,
861 "Configuration seems sane. Control-socket, hook-libraries, and D2 "
862 "configuration were sanity checked, but not applied.");
863 }
864 }
865
866 // So far so good, there was no parsing error so let's commit the
867 // configuration. This will add created subnets and option values into
868 // the server's configuration.
869 // This operation should be exception safe but let's make sure.
870 if (!rollback) {
871 try {
872
873 // Setup the command channel.
875
876 // No need to commit interface names as this is handled by the
877 // CfgMgr::commit() function.
878
879 // Apply the staged D2ClientConfig, used to be done by parser commit
881 cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
883
884 // This occurs last as if it succeeds, there is no easy way to
885 // revert it. As a result, the failure to commit a subsequent
886 // change causes problems when trying to roll back.
887 HooksManager::prepareUnloadLibraries();
888 static_cast<void>(HooksManager::unloadLibraries());
889 const HooksConfig& libraries =
890 CfgMgr::instance().getStagingCfg()->getHooksConfig();
891 libraries.loadLibraries();
892 }
893 catch (const isc::Exception& ex) {
895 answer = isc::config::createAnswer(2, ex.what());
896
897 // An error occurred, so make sure to restore the original data.
898 rollback = true;
899 } catch (...) {
900 // For things like bad_cast in boost::lexical_cast
902 answer = isc::config::createAnswer(2, "undefined configuration"
903 " parsing error");
904
905 // An error occurred, so make sure to restore the original data.
906 rollback = true;
907 }
908 }
909
910 // Moved from the commit block to add the config backend indication.
911 if (!rollback) {
912 try {
913
914 // If there are config backends, fetch and merge into staging config
915 server.getCBControl()->databaseConfigFetch(srv_config,
916 CBControlDHCPv6::FetchMode::FETCH_ALL);
917 }
918 catch (const isc::Exception& ex) {
919 std::ostringstream err;
920 err << "during update from config backend database: " << ex.what();
922 answer = isc::config::createAnswer(2, err.str());
923
924 // An error occurred, so make sure to restore the original data.
925 rollback = true;
926 } catch (...) {
927 // For things like bad_cast in boost::lexical_cast
928 std::ostringstream err;
929 err << "during update from config backend database: "
930 << "undefined configuration parsing error";
932 answer = isc::config::createAnswer(2, err.str());
933
934 // An error occurred, so make sure to restore the original data.
935 rollback = true;
936 }
937 }
938
939 // Rollback changes as the configuration parsing failed.
940 if (rollback) {
941 // Revert to original configuration of runtime option definitions
942 // in the libdhcp++.
944 return (answer);
945 }
946
948 .arg(CfgMgr::instance().getStagingCfg()->
949 getConfigSummary(SrvConfig::CFGSEL_ALL6));
950
951 // Everything was fine. Configuration is successful.
952 answer = isc::config::createAnswer(0, "Configuration successful.");
953 return (answer);
954}
955
956} // namespace dhcp
957} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void closeCommandSocket()
Shuts down any open control sockets.
Definition: command_mgr.cc:628
static CommandMgr & instance()
CommandMgr is a singleton class.
Definition: command_mgr.cc:651
void openCommandSocket(const isc::data::ConstElementPtr &socket_info)
Opens control socket with parameters specified in socket_info.
Definition: command_mgr.cc:624
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
uint16_t getUint16(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint16_t.
Parse Database Parameters.
void parse(std::string &access_string, isc::data::ConstElementPtr database_config)
Parse configuration value.
static void moveReservationMode(isc::data::ElementPtr config)
Moves deprecated reservation-mode parameter to new reservations flags.
Wrapper class that holds MAC/hardware address sources.
void setD2ClientConfig(D2ClientConfigPtr &new_config)
Updates the DHCP-DDNS client configuration to the given value.
Definition: cfgmgr.cc:41
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
Parser for a list of client class definitions.
ClientClassDictionaryPtr parse(isc::data::ConstElementPtr class_def_list, uint16_t family, bool check_dependencies=true)
Parse configuration entries.
Parser for the control-socket structure.
Definition: dhcp_parsers.h:211
void parse(SrvConfig &srv_cfg, isc::data::ConstElementPtr value)
"Parses" control-socket structure
Definition: dhcp_parsers.cc:77
Parser for D2ClientConfig.
Definition: dhcp_parsers.h:981
D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg)
Parses a given dhcp-ddns element into D2ClientConfig.
static size_t setAllDefaults(isc::data::ConstElementPtr d2_config)
Sets all defaults for D2 client configuration.
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:56
Parser for the configuration of DHCP packet queue controls.
data::ElementPtr parse(const isc::data::ConstElementPtr &control_elem)
Parses content of the "dhcp-queue-control".
Parser for server DUID configuration.
void parse(const CfgDUIDPtr &cfg, isc::data::ConstElementPtr duid_configuration)
Parses DUID configuration.
To be removed. Please use ConfigError instead.
DHCPv6 server service.
Definition: dhcp6_srv.h:66
CBControlDHCPv6Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp6_srv.h:124
void discardPackets()
Discards parked packets Clears the packet parking lots of all packets.
Definition: dhcp6_srv.cc:4259
Parser for the configuration parameters pertaining to the processing of expired leases.
void parse(isc::data::ConstElementPtr expiration_config)
Parses parameters in the JSON map, pertaining to the processing of the expired leases.
static void printRegistered()
Prints out all registered backends.
Parser for a list of host identifiers for DHCPv6.
void parse(isc::data::ConstElementPtr ids_list)
Parses a list of host identifiers.
Parser for a list of host reservations for a subnet.
void parse(const SubnetID &subnet_id, isc::data::ConstElementPtr hr_list, HostCollection &hosts_list)
Parses a list of host reservation entries for a subnet.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
void closeSockets()
Closes all open sockets.
Definition: iface_mgr.cc:286
Parser for the configuration of interfaces.
void parse(const CfgIfacePtr &config, const isc::data::ConstElementPtr &values)
Parses content of the "interfaces-config".
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition: libdhcp++.cc:214
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
Definition: libdhcp++.cc:235
parser for MAC/hardware acquisition sources
Definition: dhcp_parsers.h:195
void parse(CfgMACSource &mac_sources, isc::data::ConstElementPtr value)
parses parameters value
Definition: dhcp_parsers.cc:46
Simple parser for multi-threading structure.
void parse(SrvConfig &srv_cfg, const isc::data::ConstElementPtr &value)
parses JSON structure.
Parser for option data values within a subnet.
void parse(const CfgOptionPtr &cfg, isc::data::ConstElementPtr option_data_list)
Parses a list of options, instantiates them and stores in cfg.
Parser for a list of option definitions.
Definition: dhcp_parsers.h:254
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list)
Parses a list of option definitions, create them and store in cfg.
Class of option definition space container.
Simple parser for sanity-checks structure.
void parse(SrvConfig &srv_cfg, const isc::data::ConstElementPtr &value)
parses JSON structure
Parser for a list of shared networks.
void parse(CfgSharedNetworksTypePtr &cfg, const data::ConstElementPtr &shared_networks_list_data)
Parses a list of shared networks.
static size_t deriveParameters(isc::data::ElementPtr global)
Derives (inherits) all parameters from global to more specific scopes.
static size_t setAllDefaults(isc::data::ElementPtr global)
Sets all defaults for DHCPv6 configuration.
static const uint32_t CFGSEL_ALL6
IPv6 related config.
Definition: srv_config.h:193
static void resetSubnetID()
Resets subnet-id counter to its initial value (1).
Definition: subnet.h:241
this class parses a list of DHCP6 subnets
Definition: dhcp_parsers.h:929
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list)
parses contents of the list
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
Wrapper class that holds hooks libraries configuration.
Definition: hooks_config.h:36
void verifyLibraries(const isc::data::Element::Position &position) const
Verifies that libraries stored in libraries_ are valid.
Definition: hooks_config.cc:20
void loadLibraries() const
Commits hooks libraries configuration.
Definition: hooks_config.cc:55
Parser for hooks library list.
Definition: hooks_parser.h:21
void parse(HooksConfig &libraries, isc::data::ConstElementPtr value)
Parses parameters value.
Definition: hooks_parser.cc:28
Implements parser for config control information, "config-control".
ConfigControlInfoPtr parse(const data::ConstElementPtr &config_control)
Parses a configuration control Element.
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:257
Parsers for client class definitions.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Logging initialization functions.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
void configureCommandChannel()
Initialize the command channel based on the staging configuration.
boost::shared_ptr< CfgDUID > CfgDUIDPtr
Pointer to the Non-const object.
Definition: cfg_duid.h:161
std::pair< std::string, isc::data::ConstElementPtr > ConfigPair
Combination of parameter name and configuration contents.
Definition: dhcp_parsers.h:175
const isc::log::MessageID DHCP6_PARSER_FAIL
const isc::log::MessageID DHCP6_PARSER_EXCEPTION
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configures DHCPv6 server.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:706
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.
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
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:28
const isc::log::MessageID DHCP6_CONFIG_COMPLETE
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
boost::shared_ptr< CfgIface > CfgIfacePtr
A pointer to the CfgIface .
Definition: cfg_iface.h:387
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1044
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
Definition: cfg_subnets6.h:330
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:794
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< ClientClassDictionary > ClientClassDictionaryPtr
Defines a pointer to a ClientClassDictionary.
boost::shared_ptr< CfgSharedNetworks6 > CfgSharedNetworks6Ptr
Pointer to the configuration of IPv6 shared networks.
const isc::log::MessageID DHCP6_PARSER_COMMIT_EXCEPTION
const isc::log::MessageID DHCP6_CONFIG_START
const isc::log::MessageID DHCP6_PARSER_COMMIT_FAIL
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:88
boost::shared_ptr< ConfigControlInfo > ConfigControlInfoPtr
Defines a pointer to a ConfigControlInfo.
Defines the logger used by the top-level component of kea-lfc.
#define DHCP6_OPTION_SPACE