2020-03-23 09:09:42 +01:00
|
|
|
// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
|
2012-10-11 19:08:23 +02:00
|
|
|
//
|
2015-12-15 21:37:34 +01:00
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2015-04-18 01:39:43 +02:00
|
|
|
#include <config.h>
|
|
|
|
|
2015-06-10 10:48:24 +02:00
|
|
|
#include <cc/command_interpreter.h>
|
2018-08-29 13:54:05 +02:00
|
|
|
#include <database/dbaccess_parser.h>
|
2019-01-24 10:16:19 -05:00
|
|
|
#include <database/backend_selector.h>
|
|
|
|
#include <database/server_selector.h>
|
2012-10-11 19:08:23 +02:00
|
|
|
#include <dhcp4/dhcp4_log.h>
|
2018-05-15 15:56:18 -04:00
|
|
|
#include <dhcp4/dhcp4_srv.h>
|
2018-10-16 13:21:20 -04:00
|
|
|
#include <dhcp4/json_config_parser.h>
|
2020-04-16 14:42:34 +03:00
|
|
|
#include <dhcp/libdhcp++.h>
|
|
|
|
#include <dhcp/option_definition.h>
|
2019-03-19 13:26:00 +01:00
|
|
|
#include <dhcpsrv/cb_ctl_dhcp4.h>
|
2014-09-22 16:38:14 +02:00
|
|
|
#include <dhcpsrv/cfg_option.h>
|
2012-12-14 12:50:23 +01:00
|
|
|
#include <dhcpsrv/cfgmgr.h>
|
2018-10-16 13:21:20 -04:00
|
|
|
#include <dhcpsrv/config_backend_dhcp4_mgr.h>
|
2018-03-08 02:49:19 +01:00
|
|
|
#include <dhcpsrv/db_type.h>
|
2017-09-13 00:30:32 +02:00
|
|
|
#include <dhcpsrv/parsers/client_class_def_parser.h>
|
2014-11-26 19:23:32 +01:00
|
|
|
#include <dhcpsrv/parsers/dhcp_parsers.h>
|
2015-10-02 15:36:40 +02:00
|
|
|
#include <dhcpsrv/parsers/expiration_config_parser.h>
|
2014-11-27 15:24:08 +01:00
|
|
|
#include <dhcpsrv/parsers/host_reservation_parser.h>
|
|
|
|
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
|
2015-02-06 20:36:14 +01:00
|
|
|
#include <dhcpsrv/parsers/ifaces_config_parser.h>
|
2020-04-09 14:24:41 +03:00
|
|
|
#include <dhcpsrv/parsers/multi_threading_config_parser.h>
|
2017-07-25 09:55:14 +02:00
|
|
|
#include <dhcpsrv/parsers/option_data_parser.h>
|
2018-11-07 18:07:34 -05:00
|
|
|
#include <dhcpsrv/parsers/dhcp_queue_control_parser.h>
|
2017-07-25 14:33:24 +02:00
|
|
|
#include <dhcpsrv/parsers/simple_parser4.h>
|
2017-09-13 00:30:32 +02:00
|
|
|
#include <dhcpsrv/parsers/shared_networks_list_parser.h>
|
2018-07-24 20:42:04 +02:00
|
|
|
#include <dhcpsrv/parsers/sanity_checks_parser.h>
|
2020-04-16 14:42:34 +03:00
|
|
|
#include <dhcpsrv/host_data_source_factory.h>
|
2015-09-28 13:01:30 +02:00
|
|
|
#include <dhcpsrv/timer_mgr.h>
|
2018-09-28 16:41:11 -04:00
|
|
|
#include <process/config_ctl_parser.h>
|
2020-06-25 15:29:33 +02:00
|
|
|
#include <hooks/hooks_manager.h>
|
2017-02-14 15:06:28 +01:00
|
|
|
#include <hooks/hooks_parser.h>
|
2015-06-03 16:32:59 +02:00
|
|
|
#include <config/command_mgr.h>
|
2012-12-14 12:50:23 +01:00
|
|
|
#include <util/encode/hex.h>
|
2012-12-21 13:11:53 +01:00
|
|
|
#include <util/strutil.h>
|
2013-04-10 17:02:10 -04:00
|
|
|
|
2012-12-12 13:02:40 +01:00
|
|
|
#include <boost/foreach.hpp>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
2020-04-16 14:42:34 +03:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2013-04-10 17:02:10 -04:00
|
|
|
|
2020-04-02 19:49:27 +03:00
|
|
|
#include <limits>
|
2020-04-16 14:42:34 +03:00
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
2016-10-05 20:56:42 +02:00
|
|
|
#include <netinet/in.h>
|
2012-12-05 15:27:30 +01:00
|
|
|
#include <vector>
|
2020-04-16 14:42:34 +03:00
|
|
|
#include <map>
|
2012-12-05 15:27:30 +01:00
|
|
|
|
2012-10-11 19:08:23 +02:00
|
|
|
using namespace std;
|
2012-12-21 12:07:43 +01:00
|
|
|
using namespace isc;
|
2020-04-02 19:49:27 +03:00
|
|
|
using namespace isc::dhcp;
|
2020-04-16 14:42:34 +03:00
|
|
|
using namespace isc::data;
|
2012-10-11 19:08:23 +02:00
|
|
|
using namespace isc::asiolink;
|
2017-03-04 15:42:24 +01:00
|
|
|
using namespace isc::hooks;
|
2018-10-16 13:21:20 -04:00
|
|
|
using namespace isc::process;
|
2018-10-17 15:05:27 -04:00
|
|
|
using namespace isc::config;
|
2019-01-24 10:16:19 -05:00
|
|
|
using namespace isc::db;
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2012-12-21 12:07:43 +01:00
|
|
|
namespace {
|
|
|
|
|
2017-09-13 00:30:32 +02:00
|
|
|
/// @brief Parser that takes care of global DHCPv4 parameters and utility
|
|
|
|
/// functions that work on global level.
|
|
|
|
///
|
|
|
|
/// This class is a collection of utility method that either handle
|
|
|
|
/// global parameters (see @ref parse), or conducts operations on
|
|
|
|
/// global level (see @ref sanityChecks and @ref copySubnets4).
|
2017-01-26 15:20:08 +01:00
|
|
|
///
|
|
|
|
/// See @ref parse method for a list of supported parameters.
|
2017-01-26 01:26:10 +01:00
|
|
|
class Dhcp4ConfigParser : public isc::data::SimpleParser {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/// @brief Sets global parameters in staging configuration
|
|
|
|
///
|
|
|
|
/// @param global global configuration scope
|
2017-01-26 15:00:35 +01:00
|
|
|
/// @param cfg Server configuration (parsed parameters will be stored here)
|
2017-01-26 01:26:10 +01:00
|
|
|
///
|
|
|
|
/// Currently this method sets the following global parameters:
|
|
|
|
///
|
|
|
|
/// - echo-client-id
|
|
|
|
/// - decline-probation-period
|
|
|
|
/// - dhcp4o6-port
|
2017-11-29 08:09:49 +01:00
|
|
|
/// - user-context
|
2017-01-26 01:26:10 +01:00
|
|
|
///
|
|
|
|
/// @throw DhcpConfigError if parameters are missing or
|
|
|
|
/// or having incorrect values.
|
2017-09-13 21:04:25 +02:00
|
|
|
void parse(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
|
2017-01-26 01:26:10 +01:00
|
|
|
|
|
|
|
// Set whether v4 server is supposed to echo back client-id
|
|
|
|
// (yes = RFC6842 compatible, no = backward compatibility)
|
|
|
|
bool echo_client_id = getBoolean(global, "echo-client-id");
|
2017-02-11 10:29:40 +01:00
|
|
|
cfg->setEchoClientId(echo_client_id);
|
2017-01-26 01:26:10 +01:00
|
|
|
|
2017-01-26 21:45:23 +01:00
|
|
|
// Set the probation period for decline handling.
|
|
|
|
uint32_t probation_period =
|
|
|
|
getUint32(global, "decline-probation-period");
|
|
|
|
cfg->setDeclinePeriod(probation_period);
|
|
|
|
|
|
|
|
// Set the DHCPv4-over-DHCPv6 interserver port.
|
2017-03-05 09:03:09 +01:00
|
|
|
uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
|
2017-01-26 21:45:23 +01:00
|
|
|
cfg->setDhcp4o6Port(dhcp4o6_port);
|
2017-11-29 08:09:49 +01:00
|
|
|
|
|
|
|
// Set the global user context.
|
|
|
|
ConstElementPtr user_context = global->get("user-context");
|
|
|
|
if (user_context) {
|
|
|
|
cfg->setContext(user_context);
|
|
|
|
}
|
2018-10-01 14:17:59 -04:00
|
|
|
|
|
|
|
// Set the server's logical name
|
|
|
|
std::string server_tag = getString(global, "server-tag");
|
|
|
|
cfg->setServerTag(server_tag);
|
2017-01-26 01:26:10 +01:00
|
|
|
}
|
2017-09-13 00:30:32 +02:00
|
|
|
|
2020-10-02 17:36:31 +02:00
|
|
|
/// @brief Sets global parameters before other parameters are parsed.
|
|
|
|
///
|
|
|
|
/// This method sets selected global parameters before other parameters
|
|
|
|
/// are parsed. This is important when the bahavior of the parsers
|
|
|
|
/// run later depends on these global paramters.
|
|
|
|
///
|
|
|
|
/// Currently this method sets the following global parameters:
|
|
|
|
/// - ip-reservations-unique
|
|
|
|
///
|
|
|
|
/// @param global global configuration scope
|
|
|
|
/// @param cfg Server configuration (parsed parameters will be stored here)
|
|
|
|
void parseEarly(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
|
|
|
|
// Set ip-reservations-unique flag.
|
|
|
|
bool ip_reservations_unique = getBoolean(global, "ip-reservations-unique");
|
|
|
|
cfg->setIPReservationsUnique(ip_reservations_unique);
|
|
|
|
}
|
|
|
|
|
2017-09-13 00:30:32 +02:00
|
|
|
/// @brief Copies subnets from shared networks to regular subnets container
|
|
|
|
///
|
|
|
|
/// @param from pointer to shared networks container (copy from here)
|
|
|
|
/// @param dest pointer to cfg subnets4 (copy to here)
|
|
|
|
/// @throw BadValue if any pointer is missing
|
|
|
|
/// @throw DhcpConfigError if there are duplicates (or other subnet defects)
|
|
|
|
void
|
2017-09-13 21:04:25 +02:00
|
|
|
copySubnets4(const CfgSubnets4Ptr& dest, const CfgSharedNetworks4Ptr& from) {
|
2017-09-13 00:30:32 +02:00
|
|
|
|
|
|
|
if (!dest || !from) {
|
|
|
|
isc_throw(BadValue, "Unable to copy subnets: at least one pointer is null");
|
|
|
|
}
|
|
|
|
|
|
|
|
const SharedNetwork4Collection* networks = from->getAll();
|
|
|
|
if (!networks) {
|
|
|
|
// Nothing to copy. Technically, it should return a pointer to empty
|
|
|
|
// container, but let's handle null pointer as well.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's go through all the networks one by one
|
|
|
|
for (auto net = networks->begin(); net != networks->end(); ++net) {
|
|
|
|
|
|
|
|
// For each network go through all the subnets in it.
|
|
|
|
const Subnet4Collection* subnets = (*net)->getAllSubnets();
|
|
|
|
if (!subnets) {
|
|
|
|
// Shared network without subnets it weird, but we decided to
|
|
|
|
// accept such configurations.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For each subnet, add it to a list of regular subnets.
|
|
|
|
for (auto subnet = subnets->begin(); subnet != subnets->end(); ++subnet) {
|
|
|
|
dest->add(*subnet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Conducts global sanity checks
|
|
|
|
///
|
2017-09-13 14:17:37 +02:00
|
|
|
/// This method is very simple now, but more sanity checks are expected
|
2017-09-13 00:30:32 +02:00
|
|
|
/// in the future.
|
|
|
|
///
|
|
|
|
/// @param cfg - the parsed structure
|
|
|
|
/// @param global global Dhcp4 scope
|
|
|
|
/// @throw DhcpConfigError in case of issues found
|
|
|
|
void
|
2017-09-13 21:04:25 +02:00
|
|
|
sanityChecks(const SrvConfigPtr& cfg, const ConstElementPtr& global) {
|
2017-09-13 00:30:32 +02:00
|
|
|
|
|
|
|
/// Shared network sanity checks
|
|
|
|
const SharedNetwork4Collection* networks = cfg->getCfgSharedNetworks4()->getAll();
|
|
|
|
if (networks) {
|
|
|
|
sharedNetworksSanityChecks(*networks, global->get("shared-networks"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Sanity checks for shared networks
|
|
|
|
///
|
|
|
|
/// This method verifies if there are no issues with shared networks.
|
|
|
|
/// @param networks pointer to shared networks being checked
|
|
|
|
/// @param json shared-networks element
|
|
|
|
/// @throw DhcpConfigError if issues are encountered
|
|
|
|
void
|
|
|
|
sharedNetworksSanityChecks(const SharedNetwork4Collection& networks,
|
|
|
|
ConstElementPtr json) {
|
|
|
|
|
2017-09-13 10:38:27 +02:00
|
|
|
/// @todo: in case of errors, use json to extract line numbers.
|
|
|
|
if (!json) {
|
|
|
|
// No json? That means that the shared-networks was never specified
|
|
|
|
// in the config.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-13 00:30:32 +02:00
|
|
|
// Used for names uniqueness checks.
|
|
|
|
std::set<string> names;
|
|
|
|
|
|
|
|
// Let's go through all the networks one by one
|
|
|
|
for (auto net = networks.begin(); net != networks.end(); ++net) {
|
|
|
|
string txt;
|
|
|
|
|
|
|
|
// Let's check if all subnets have either the same interface
|
|
|
|
// or don't have the interface specified at all.
|
2018-10-19 17:17:09 +02:00
|
|
|
bool authoritative = (*net)->getAuthoritative();
|
2019-03-11 00:13:47 +01:00
|
|
|
string iface = (*net)->getIface();
|
2017-09-13 00:30:32 +02:00
|
|
|
|
|
|
|
const Subnet4Collection* subnets = (*net)->getAllSubnets();
|
|
|
|
if (subnets) {
|
|
|
|
// For each subnet, add it to a list of regular subnets.
|
|
|
|
for (auto subnet = subnets->begin(); subnet != subnets->end(); ++subnet) {
|
2019-03-11 00:13:47 +01:00
|
|
|
if ((*subnet)->getAuthoritative() != authoritative) {
|
|
|
|
isc_throw(DhcpConfigError, "Subnet " << boolalpha
|
|
|
|
<< (*subnet)->toText()
|
|
|
|
<< " has different authoritative setting "
|
|
|
|
<< (*subnet)->getAuthoritative()
|
|
|
|
<< " than the shared-network itself: "
|
|
|
|
<< authoritative);
|
|
|
|
}
|
|
|
|
|
2017-09-13 00:30:32 +02:00
|
|
|
if (iface.empty()) {
|
|
|
|
iface = (*subnet)->getIface();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*subnet)->getIface().empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-02-26 12:45:14 +01:00
|
|
|
if ((*subnet)->getIface() != iface) {
|
2017-09-13 00:30:32 +02:00
|
|
|
isc_throw(DhcpConfigError, "Subnet " << (*subnet)->toText()
|
|
|
|
<< " has specified interface " << (*subnet)->getIface()
|
|
|
|
<< ", but earlier subnet in the same shared-network"
|
|
|
|
<< " or the shared-network itself used " << iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's collect the subnets in case we later find out the
|
|
|
|
// subnet doesn't have a mandatory name.
|
|
|
|
txt += (*subnet)->toText() + " ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next, let's check name of the shared network.
|
|
|
|
if ((*net)->getName().empty()) {
|
|
|
|
isc_throw(DhcpConfigError, "Shared-network with subnets "
|
|
|
|
<< txt << " is missing mandatory 'name' parameter");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is it unique?
|
|
|
|
if (names.find((*net)->getName()) != names.end()) {
|
|
|
|
isc_throw(DhcpConfigError, "A shared-network with "
|
|
|
|
"name " << (*net)->getName() << " defined twice.");
|
|
|
|
}
|
|
|
|
names.insert((*net)->getName());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2017-01-26 01:26:10 +01:00
|
|
|
};
|
|
|
|
|
2012-12-21 12:07:43 +01:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
namespace isc {
|
|
|
|
namespace dhcp {
|
|
|
|
|
2016-12-09 16:08:24 -05:00
|
|
|
/// @brief Initialize the command channel based on the staging configuration
|
|
|
|
///
|
|
|
|
/// Only close the current channel, if the new channel configuration is
|
|
|
|
/// different. This avoids disconnecting a client and hence not sending them
|
|
|
|
/// a command result, unless they specifically alter the channel configuration.
|
|
|
|
/// In that case the user simply has to accept they'll be disconnected.
|
|
|
|
///
|
|
|
|
void configureCommandChannel() {
|
|
|
|
// Get new socket configuration.
|
|
|
|
ConstElementPtr sock_cfg =
|
|
|
|
CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
|
|
|
|
|
|
|
|
// Get current socket configuration.
|
|
|
|
ConstElementPtr current_sock_cfg =
|
|
|
|
CfgMgr::instance().getCurrentCfg()->getControlSocketInfo();
|
|
|
|
|
|
|
|
// Determine if the socket configuration has changed. It has if
|
|
|
|
// both old and new configuration is specified but respective
|
2017-07-23 11:23:40 -04:00
|
|
|
// data elements aren't equal.
|
2016-12-09 16:08:24 -05:00
|
|
|
bool sock_changed = (sock_cfg && current_sock_cfg &&
|
|
|
|
!sock_cfg->equals(*current_sock_cfg));
|
|
|
|
|
|
|
|
// If the previous or new socket configuration doesn't exist or
|
|
|
|
// the new configuration differs from the old configuration we
|
2017-07-23 12:54:55 -04:00
|
|
|
// close the existing socket and open a new socket as appropriate.
|
2017-12-02 16:28:34 +01:00
|
|
|
// Note that closing an existing socket means the client will not
|
2016-12-09 16:08:24 -05:00
|
|
|
// receive the configuration result.
|
|
|
|
if (!sock_cfg || !current_sock_cfg || sock_changed) {
|
|
|
|
// Close the existing socket (if any).
|
|
|
|
isc::config::CommandMgr::instance().closeCommandSocket();
|
|
|
|
|
|
|
|
if (sock_cfg) {
|
|
|
|
// This will create a control socket and install the external
|
|
|
|
// socket in IfaceMgr. That socket will be monitored when
|
|
|
|
// Dhcp4Srv::receivePacket() calls IfaceMgr::receive4() and
|
|
|
|
// callback in CommandMgr will be called, if necessary.
|
|
|
|
isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-11 19:08:23 +02:00
|
|
|
isc::data::ConstElementPtr
|
2018-05-15 15:56:18 -04:00
|
|
|
configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
|
2017-02-13 17:34:43 +01:00
|
|
|
bool check_only) {
|
2012-10-11 19:08:23 +02:00
|
|
|
if (!config_set) {
|
2018-10-17 15:05:27 -04:00
|
|
|
ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR,
|
2012-12-05 15:27:30 +01:00
|
|
|
string("Can't parse NULL config"));
|
|
|
|
return (answer);
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
|
|
|
|
2013-07-11 10:34:43 +02:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND,
|
2013-05-01 07:39:08 -04:00
|
|
|
DHCP4_CONFIG_START).arg(config_set->str());
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2013-12-30 18:38:37 +01:00
|
|
|
// Before starting any subnet operations, let's reset the subnet-id counter,
|
|
|
|
// so newly recreated configuration starts with first subnet-id equal 1.
|
|
|
|
Subnet::resetSubnetID();
|
|
|
|
|
2020-07-23 21:21:02 +02:00
|
|
|
// Close DHCP sockets and remove any existing timers.
|
2017-04-19 16:34:46 +02:00
|
|
|
if (!check_only) {
|
2020-07-23 21:21:02 +02:00
|
|
|
IfaceMgr::instance().closeSockets();
|
2017-04-19 16:34:46 +02:00
|
|
|
TimerMgr::instance()->unregisterTimers();
|
2018-05-16 14:42:55 +02:00
|
|
|
server.discardPackets();
|
2019-03-19 13:58:08 +01:00
|
|
|
server.getCBControl()->reset();
|
2017-04-19 16:34:46 +02:00
|
|
|
}
|
2015-09-28 13:01:30 +02:00
|
|
|
|
2015-11-24 20:26:08 +01:00
|
|
|
// Revert any runtime option definitions configured so far and not committed.
|
|
|
|
LibDHCP::revertRuntimeOptionDefs();
|
2015-11-25 16:44:46 +01:00
|
|
|
// Let's set empty container in case a user hasn't specified any configuration
|
2017-07-23 11:56:50 -04:00
|
|
|
// for option definitions. This is equivalent to committing empty container.
|
2015-11-25 16:44:46 +01:00
|
|
|
LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
|
2015-11-24 20:26:08 +01:00
|
|
|
|
2018-03-27 19:22:45 +02:00
|
|
|
// Print the list of known backends.
|
|
|
|
HostDataSourceFactory::printRegistered();
|
|
|
|
|
2013-05-01 07:39:08 -04:00
|
|
|
// Answer will hold the result.
|
2012-12-21 12:53:31 +01:00
|
|
|
ConstElementPtr answer;
|
2015-01-22 11:28:13 +01:00
|
|
|
// Rollback informs whether error occurred and original data
|
2012-12-21 12:53:31 +01:00
|
|
|
// have to be restored to global storages.
|
|
|
|
bool rollback = false;
|
2020-05-22 10:34:36 +02:00
|
|
|
// Global parameter name in case of an error.
|
|
|
|
string parameter_name;
|
2018-10-16 13:21:20 -04:00
|
|
|
ElementPtr mutable_cfg;
|
|
|
|
SrvConfigPtr srv_cfg;
|
2012-10-11 19:08:23 +02:00
|
|
|
try {
|
2020-04-16 14:42:34 +03:00
|
|
|
// Get the staging configuration
|
2018-10-16 13:21:20 -04:00
|
|
|
srv_cfg = CfgMgr::instance().getStagingCfg();
|
2017-01-25 15:00:15 +01:00
|
|
|
|
2016-11-29 20:09:14 +01:00
|
|
|
// This is a way to convert ConstElementPtr to ElementPtr.
|
|
|
|
// We need a config that can be edited, because we will insert
|
|
|
|
// default values and will insert derived values as well.
|
2018-10-16 13:21:20 -04:00
|
|
|
mutable_cfg = boost::const_pointer_cast<Element>(config_set);
|
2016-11-29 20:09:14 +01:00
|
|
|
|
2020-10-15 18:43:46 +03:00
|
|
|
bool found = false;
|
|
|
|
ConstElementPtr reservations_out_of_pool = mutable_cfg->get("reservations-out-of-pool");
|
|
|
|
ConstElementPtr reservations_in_subnet = mutable_cfg->get("reservations-in-subnet");
|
|
|
|
ConstElementPtr reservations_global = mutable_cfg->get("reservations-global");
|
2020-10-27 19:49:22 +02:00
|
|
|
if (reservations_out_of_pool || reservations_in_subnet || reservations_global) {
|
2020-10-15 18:43:46 +03:00
|
|
|
found = true;
|
|
|
|
}
|
2020-10-12 21:20:24 +03:00
|
|
|
ConstElementPtr reservation_mode = mutable_cfg->get("reservation-mode");
|
|
|
|
if (reservation_mode) {
|
2020-10-28 10:06:24 +02:00
|
|
|
LOG_WARN(dhcp4_logger, DHCP4_DEPRECATED_RESERVATION_MODE);
|
2020-10-15 12:52:51 +03:00
|
|
|
if (found) {
|
2020-10-12 21:20:24 +03:00
|
|
|
isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'"
|
2020-10-15 12:52:51 +03:00
|
|
|
" and one of 'reservations-out-of-pool'"
|
|
|
|
" , 'reservations-in-subnet' or"
|
|
|
|
" 'reservations-global' parameters");
|
2020-10-12 21:20:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-15 18:43:46 +03:00
|
|
|
// reset all other reservation flags to overwrite default values.
|
|
|
|
if (found) {
|
2020-10-27 19:49:22 +02:00
|
|
|
bool force_true = false;
|
2020-10-15 18:43:46 +03:00
|
|
|
if (!reservations_out_of_pool) {
|
|
|
|
mutable_cfg->set("reservations-out-of-pool", Element::create(false));
|
2020-10-27 19:49:22 +02:00
|
|
|
} else {
|
|
|
|
force_true = reservations_out_of_pool->boolValue();
|
2020-10-15 18:43:46 +03:00
|
|
|
}
|
|
|
|
if (!reservations_in_subnet) {
|
2020-10-27 19:49:22 +02:00
|
|
|
if (force_true) {
|
|
|
|
mutable_cfg->set("reservations-in-subnet", Element::create(true));
|
|
|
|
} else {
|
|
|
|
mutable_cfg->set("reservations-in-subnet", Element::create(false));
|
|
|
|
}
|
|
|
|
} else if (force_true && !reservations_in_subnet->boolValue()) {
|
|
|
|
isc_throw(DhcpConfigError, "invalid use of disabled 'reservations-in-subnet'"
|
|
|
|
" when enabled 'reservations-out-of-pool'");
|
2020-10-15 18:43:46 +03:00
|
|
|
}
|
|
|
|
if (!reservations_global) {
|
|
|
|
mutable_cfg->set("reservations-global", Element::create(false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-03 15:11:07 -04:00
|
|
|
// Relocate dhcp-ddns parameters that have moved to global scope.
|
|
|
|
// Rule is that a global value overrides the dhcp-ddns value, so
|
|
|
|
// we need to do this before we apply global defaults.
|
2020-04-02 19:49:27 +03:00
|
|
|
// Note this is done for backward compatibility.
|
2019-10-03 15:11:07 -04:00
|
|
|
srv_cfg->moveDdnsParams(mutable_cfg);
|
|
|
|
|
2016-11-29 20:09:14 +01:00
|
|
|
// Set all default values if not specified by the user.
|
2016-12-22 16:20:34 +01:00
|
|
|
SimpleParser4::setAllDefaults(mutable_cfg);
|
2016-11-29 20:09:14 +01:00
|
|
|
|
2017-01-23 15:39:49 +01:00
|
|
|
// And now derive (inherit) global parameters to subnets, if not specified.
|
|
|
|
SimpleParser4::deriveParameters(mutable_cfg);
|
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// In principle we could have the following code structured as a series
|
|
|
|
// of long if else if clauses. That would give a marginal performance
|
|
|
|
// boost, but would make the code less readable. We had serious issues
|
|
|
|
// with the parser code debugability, so I decided to keep it as a
|
|
|
|
// series of independent ifs.
|
|
|
|
|
2020-10-02 17:36:31 +02:00
|
|
|
// This parser is used in several places.
|
|
|
|
Dhcp4ConfigParser global_parser;
|
|
|
|
|
|
|
|
// Apply global options in the staging config, e.g. ip-reservations-unique
|
|
|
|
global_parser.parseEarly(srv_cfg, mutable_cfg);
|
|
|
|
|
2020-10-29 12:29:46 +02:00
|
|
|
// If using deprecated reservation-mode, remove defaults for new parameters
|
|
|
|
// reservations-out-of-pool, reservations-in-subnet and reservations-global.
|
|
|
|
if (reservation_mode) {
|
|
|
|
mutable_cfg->remove("reservations-out-of-pool");
|
|
|
|
mutable_cfg->remove("reservations-in-subnet");
|
|
|
|
mutable_cfg->remove("reservations-global");
|
|
|
|
}
|
|
|
|
|
2016-11-29 20:09:14 +01:00
|
|
|
// We need definitions first
|
|
|
|
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
|
|
|
if (option_defs) {
|
2020-05-22 10:34:36 +02:00
|
|
|
parameter_name = "option-def";
|
2019-02-26 21:57:53 +01:00
|
|
|
OptionDefListParser parser(AF_INET);
|
2017-01-25 15:00:15 +01:00
|
|
|
CfgOptionDefPtr cfg_option_def = srv_cfg->getCfgOptionDef();
|
2016-11-29 20:09:14 +01:00
|
|
|
parser.parse(cfg_option_def, option_defs);
|
|
|
|
}
|
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr option_datas = mutable_cfg->get("option-data");
|
|
|
|
if (option_datas) {
|
|
|
|
parameter_name = "option-data";
|
|
|
|
OptionDataListParser parser(AF_INET);
|
|
|
|
CfgOptionPtr cfg_option = srv_cfg->getCfgOption();
|
|
|
|
parser.parse(cfg_option, option_datas);
|
|
|
|
}
|
2019-06-11 02:10:18 +02:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr control_socket = mutable_cfg->get("control-socket");
|
|
|
|
if (control_socket) {
|
|
|
|
parameter_name = "control-socket";
|
|
|
|
ControlSocketParser parser;
|
|
|
|
parser.parse(*srv_cfg, control_socket);
|
|
|
|
}
|
2016-11-29 20:09:14 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr multi_threading = mutable_cfg->get("multi-threading");
|
|
|
|
if (multi_threading) {
|
|
|
|
parameter_name = "multi-threading";
|
|
|
|
MultiThreadingConfigParser parser;
|
|
|
|
parser.parse(*srv_cfg, multi_threading);
|
|
|
|
}
|
2016-11-29 20:09:14 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr queue_control = mutable_cfg->get("dhcp-queue-control");
|
|
|
|
if (queue_control) {
|
|
|
|
parameter_name = "dhcp-queue-control";
|
|
|
|
DHCPQueueControlParser parser;
|
|
|
|
srv_cfg->setDHCPQueueControl(parser.parse(queue_control));
|
|
|
|
}
|
2017-01-04 13:09:28 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr hr_identifiers =
|
|
|
|
mutable_cfg->get("host-reservation-identifiers");
|
|
|
|
if (hr_identifiers) {
|
|
|
|
parameter_name = "host-reservation-identifiers";
|
|
|
|
HostReservationIdsParser4 parser;
|
|
|
|
parser.parse(hr_identifiers);
|
|
|
|
}
|
2018-11-01 11:19:55 -04:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr ifaces_config = mutable_cfg->get("interfaces-config");
|
|
|
|
if (ifaces_config) {
|
|
|
|
parameter_name = "interfaces-config";
|
2020-07-20 17:02:00 +02:00
|
|
|
IfacesConfigParser parser(AF_INET, check_only);
|
2020-05-22 10:34:36 +02:00
|
|
|
CfgIfacePtr cfg_iface = srv_cfg->getCfgIface();
|
|
|
|
parser.parse(cfg_iface, ifaces_config);
|
|
|
|
}
|
2020-04-09 00:42:32 +03:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr sanity_checks = mutable_cfg->get("sanity-checks");
|
|
|
|
if (sanity_checks) {
|
|
|
|
parameter_name = "sanity-checks";
|
|
|
|
SanityChecksParser parser;
|
|
|
|
parser.parse(*srv_cfg, sanity_checks);
|
|
|
|
}
|
2017-01-05 15:23:35 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr expiration_cfg =
|
|
|
|
mutable_cfg->get("expired-leases-processing");
|
|
|
|
if (expiration_cfg) {
|
|
|
|
parameter_name = "expired-leases-processing";
|
|
|
|
ExpirationConfigParser parser;
|
|
|
|
parser.parse(expiration_cfg);
|
|
|
|
}
|
2016-12-27 18:58:22 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// The hooks-libraries configuration must be parsed after parsing
|
|
|
|
// multi-threading configuration so that libraries are checked
|
|
|
|
// for multi-threading compatibility.
|
|
|
|
ConstElementPtr hooks_libraries = mutable_cfg->get("hooks-libraries");
|
|
|
|
if (hooks_libraries) {
|
|
|
|
parameter_name = "hooks-libraries";
|
|
|
|
HooksLibrariesParser hooks_parser;
|
|
|
|
HooksConfig& libraries = srv_cfg->getHooksConfig();
|
|
|
|
hooks_parser.parse(libraries, hooks_libraries);
|
|
|
|
libraries.verifyLibraries(hooks_libraries->getPosition());
|
|
|
|
}
|
2018-07-24 20:42:04 +02:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// D2 client configuration.
|
|
|
|
D2ClientConfigPtr d2_client_cfg;
|
2017-01-07 07:18:40 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// Legacy DhcpConfigParser stuff below.
|
|
|
|
ConstElementPtr dhcp_ddns = mutable_cfg->get("dhcp-ddns");
|
|
|
|
if (dhcp_ddns) {
|
|
|
|
parameter_name = "dhcp-ddns";
|
|
|
|
// Apply defaults
|
|
|
|
D2ClientConfigParser::setAllDefaults(dhcp_ddns);
|
|
|
|
D2ClientConfigParser parser;
|
|
|
|
d2_client_cfg = parser.parse(dhcp_ddns);
|
|
|
|
}
|
2017-01-23 15:39:49 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr client_classes = mutable_cfg->get("client-classes");
|
|
|
|
if (client_classes) {
|
|
|
|
parameter_name = "client-classes";
|
|
|
|
ClientClassDefListParser parser;
|
|
|
|
ClientClassDictionaryPtr dictionary =
|
|
|
|
parser.parse(client_classes, AF_INET);
|
|
|
|
srv_cfg->setClientClassDictionary(dictionary);
|
|
|
|
}
|
2017-01-11 13:47:39 -05:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// Please move at the end when migration will be finished.
|
|
|
|
ConstElementPtr lease_database = mutable_cfg->get("lease-database");
|
|
|
|
if (lease_database) {
|
|
|
|
parameter_name = "lease-database";
|
|
|
|
db::DbAccessParser parser;
|
|
|
|
std::string access_string;
|
|
|
|
parser.parse(access_string, lease_database);
|
|
|
|
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
|
|
|
|
cfg_db_access->setLeaseDbAccessString(access_string);
|
|
|
|
}
|
2017-01-25 15:00:15 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr hosts_database = mutable_cfg->get("hosts-database");
|
|
|
|
if (hosts_database) {
|
|
|
|
parameter_name = "hosts-database";
|
|
|
|
db::DbAccessParser parser;
|
|
|
|
std::string access_string;
|
|
|
|
parser.parse(access_string, hosts_database);
|
|
|
|
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
|
|
|
|
cfg_db_access->setHostDbAccessString(access_string);
|
|
|
|
}
|
2017-01-10 21:33:19 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr hosts_databases = mutable_cfg->get("hosts-databases");
|
|
|
|
if (hosts_databases) {
|
|
|
|
parameter_name = "hosts-databases";
|
|
|
|
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
|
|
|
|
db::DbAccessParser parser;
|
|
|
|
for (auto it : hosts_databases->listValue()) {
|
2018-08-29 10:52:41 +02:00
|
|
|
std::string access_string;
|
2020-05-22 10:34:36 +02:00
|
|
|
parser.parse(access_string, it);
|
2018-08-29 10:52:41 +02:00
|
|
|
cfg_db_access->setHostDbAccessString(access_string);
|
2017-01-08 17:12:20 +01:00
|
|
|
}
|
2020-05-22 10:34:36 +02:00
|
|
|
}
|
2017-01-08 17:12:20 +01:00
|
|
|
|
2020-06-12 16:22:18 +02:00
|
|
|
// Keep relative orders of shared networks and subnets.
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr shared_networks = mutable_cfg->get("shared-networks");
|
|
|
|
if (shared_networks) {
|
|
|
|
parameter_name = "shared-networks";
|
|
|
|
/// We need to create instance of SharedNetworks4ListParser
|
|
|
|
/// and parse the list of the shared networks into the
|
|
|
|
/// CfgSharedNetworks4 object. One additional step is then to
|
|
|
|
/// add subnets from the CfgSharedNetworks4 into CfgSubnets4
|
|
|
|
/// as well.
|
|
|
|
SharedNetworks4ListParser parser;
|
|
|
|
CfgSharedNetworks4Ptr cfg = srv_cfg->getCfgSharedNetworks4();
|
|
|
|
parser.parse(cfg, shared_networks);
|
|
|
|
|
|
|
|
// We also need to put the subnets it contains into normal
|
|
|
|
// subnets list.
|
|
|
|
global_parser.copySubnets4(srv_cfg->getCfgSubnets4(), cfg);
|
|
|
|
}
|
|
|
|
|
2020-06-03 20:21:00 +02:00
|
|
|
ConstElementPtr subnet4 = mutable_cfg->get("subnet4");
|
|
|
|
if (subnet4) {
|
|
|
|
parameter_name = "subnet4";
|
|
|
|
Subnets4ListConfigParser subnets_parser;
|
|
|
|
// parse() returns number of subnets parsed. We may log it one day.
|
|
|
|
subnets_parser.parse(srv_cfg, subnet4);
|
|
|
|
}
|
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr reservations = mutable_cfg->get("reservations");
|
|
|
|
if (reservations) {
|
|
|
|
parameter_name = "reservations";
|
|
|
|
HostCollection hosts;
|
|
|
|
HostReservationsListParser<HostReservationParser4> parser;
|
|
|
|
parser.parse(SUBNET_ID_GLOBAL, reservations, hosts);
|
|
|
|
for (auto h = hosts.begin(); h != hosts.end(); ++h) {
|
|
|
|
srv_cfg->getCfgHosts()->add(*h);
|
2017-09-04 19:25:15 +02:00
|
|
|
}
|
2020-05-22 10:34:36 +02:00
|
|
|
}
|
2017-09-04 19:25:15 +02:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
ConstElementPtr config_control = mutable_cfg->get("config-control");
|
|
|
|
if (config_control) {
|
|
|
|
parameter_name = "config-control";
|
|
|
|
ConfigControlParser parser;
|
|
|
|
ConfigControlInfoPtr config_ctl_info = parser.parse(config_control);
|
|
|
|
CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
|
|
|
|
}
|
[5704] host backends and kea-dhcp4/6 support global HR storage
- Added constants for special SubnetIDs:
SUBNET_ID_GLOBAL, SUBNET_ID_MAX, SUBNET_ID_UNUSED
- Modified code throughout to use these constants, rather than hard-coded
values. Note, MySQL and PostgreSQL host backends convert from NULL to
UNUSED and back.
- kea-dhcp4/6 servers will now parse a "reservations" element at the global
level.
src/lib/dhcpsrv/subnet_id.h
Added constants SubnetID SUBNET_ID_GLOBAL, SUBNET_ID_MAX, SUBNET_ID_UNUSED
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/json_config_parser.cc
kea-dhcp4 parsing now handles reservations as a global element
src/bin/dhcp4/tests/config_parser_unittest.cc
TEST_F(Dhcp4ParserTest, globalReservations) - new test to
verify global HR parsing
src/bin/dhcp4/tests/dora_unittest.cc
src/lib/dhcpsrv/cfg_hosts.cc
src/lib/dhcpsrv/host.cc
src/lib/dhcpsrv/host_mgr.cc
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/parsers/host_reservation_parser.cc
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc
src/lib/dhcpsrv/tests/alloc_engine_utils.cc
src/lib/dhcpsrv/tests/host_mgr_unittest.cc
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
src/lib/dhcpsrv/tests/host_reservations_list_parser_unittest.cc
src/lib/dhcpsrv/tests/host_unittest.cc
Replaced SubnetID 0 with SUBNET_ID_UNUSED
src/lib/dhcpsrv/srv_config.cc
SrvConfig::toElement() - added global reservations output
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc
TEST_F(CfgHostsTest, globalSubnetIDs)
TEST_F(CfgHostsTest, unusedSubnetIDs) - new tests
src/lib/dhcpsrv/tests/host_unittest.cc
Replaced SubnetID 0 with SUBNET_ID_UNUSED
TEST_F(HostTest, toText) - updated to verify global ID output
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc
TEST_F(MySqlHostDataSourceTest, globalSubnetId4)
TEST_F(MySqlHostDataSourceTest, globalSubnetId6) - new tests
src/lib/dhcpsrv/tests/srv_config_unittest.cc
TEST_F(SrvConfigTest, unparseHR) - added global HRs
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.*
GenericHostDataSourceTest::testGlobalSubnetId4()
GenericHostDataSourceTest::testGlobalSubnetId6()
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/json_config_parser.cc
kea-dhcp6 now parses reservations as a global element
src/bin/dhcp6/tests/config_parser_unittest.cc
TEST_F(Dhcp6ParserTest, globalReservations) - new test
2018-08-07 06:46:30 -04:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// Make parsers grouping.
|
|
|
|
ConfigPair config_pair;
|
|
|
|
const std::map<std::string, ConstElementPtr>& values_map =
|
2020-06-12 16:22:18 +02:00
|
|
|
mutable_cfg->mapValue();
|
2020-10-12 21:20:24 +03:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
BOOST_FOREACH(config_pair, values_map) {
|
[5704] host backends and kea-dhcp4/6 support global HR storage
- Added constants for special SubnetIDs:
SUBNET_ID_GLOBAL, SUBNET_ID_MAX, SUBNET_ID_UNUSED
- Modified code throughout to use these constants, rather than hard-coded
values. Note, MySQL and PostgreSQL host backends convert from NULL to
UNUSED and back.
- kea-dhcp4/6 servers will now parse a "reservations" element at the global
level.
src/lib/dhcpsrv/subnet_id.h
Added constants SubnetID SUBNET_ID_GLOBAL, SUBNET_ID_MAX, SUBNET_ID_UNUSED
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/json_config_parser.cc
kea-dhcp4 parsing now handles reservations as a global element
src/bin/dhcp4/tests/config_parser_unittest.cc
TEST_F(Dhcp4ParserTest, globalReservations) - new test to
verify global HR parsing
src/bin/dhcp4/tests/dora_unittest.cc
src/lib/dhcpsrv/cfg_hosts.cc
src/lib/dhcpsrv/host.cc
src/lib/dhcpsrv/host_mgr.cc
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/parsers/host_reservation_parser.cc
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc
src/lib/dhcpsrv/tests/alloc_engine_utils.cc
src/lib/dhcpsrv/tests/host_mgr_unittest.cc
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
src/lib/dhcpsrv/tests/host_reservations_list_parser_unittest.cc
src/lib/dhcpsrv/tests/host_unittest.cc
Replaced SubnetID 0 with SUBNET_ID_UNUSED
src/lib/dhcpsrv/srv_config.cc
SrvConfig::toElement() - added global reservations output
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc
TEST_F(CfgHostsTest, globalSubnetIDs)
TEST_F(CfgHostsTest, unusedSubnetIDs) - new tests
src/lib/dhcpsrv/tests/host_unittest.cc
Replaced SubnetID 0 with SUBNET_ID_UNUSED
TEST_F(HostTest, toText) - updated to verify global ID output
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc
TEST_F(MySqlHostDataSourceTest, globalSubnetId4)
TEST_F(MySqlHostDataSourceTest, globalSubnetId6) - new tests
src/lib/dhcpsrv/tests/srv_config_unittest.cc
TEST_F(SrvConfigTest, unparseHR) - added global HRs
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.*
GenericHostDataSourceTest::testGlobalSubnetId4()
GenericHostDataSourceTest::testGlobalSubnetId6()
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/json_config_parser.cc
kea-dhcp6 now parses reservations as a global element
src/bin/dhcp6/tests/config_parser_unittest.cc
TEST_F(Dhcp6ParserTest, globalReservations) - new test
2018-08-07 06:46:30 -04:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
parameter_name = config_pair.first;
|
|
|
|
|
|
|
|
// These are converted to SimpleParser and are handled already above.
|
|
|
|
if ((config_pair.first == "option-def") ||
|
|
|
|
(config_pair.first == "option-data") ||
|
|
|
|
(config_pair.first == "control-socket") ||
|
|
|
|
(config_pair.first == "multi-threading") ||
|
|
|
|
(config_pair.first == "dhcp-queue-control") ||
|
|
|
|
(config_pair.first == "host-reservation-identifiers") ||
|
|
|
|
(config_pair.first == "interfaces-config") ||
|
|
|
|
(config_pair.first == "sanity-checks") ||
|
|
|
|
(config_pair.first == "expired-leases-processing") ||
|
|
|
|
(config_pair.first == "hooks-libraries") ||
|
|
|
|
(config_pair.first == "dhcp-ddns") ||
|
|
|
|
(config_pair.first == "client-classes") ||
|
|
|
|
(config_pair.first == "lease-database") ||
|
|
|
|
(config_pair.first == "hosts-database") ||
|
|
|
|
(config_pair.first == "hosts-databases") ||
|
|
|
|
(config_pair.first == "subnet4") ||
|
|
|
|
(config_pair.first == "shared-networks") ||
|
|
|
|
(config_pair.first == "reservations") ||
|
|
|
|
(config_pair.first == "config-control")) {
|
2018-09-28 16:41:11 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-03-27 11:55:10 +01:00
|
|
|
// As of Kea 1.6.0 we have two ways of inheriting the global parameters.
|
|
|
|
// The old method is used in JSON configuration parsers when the global
|
|
|
|
// parameters are derived into the subnets and shared networks and are
|
|
|
|
// being treated as explicitly specified. The new way used by the config
|
|
|
|
// backend is the dynamic inheritance whereby each subnet and shared
|
|
|
|
// network uses a callback function to return global parameter if it
|
|
|
|
// is not specified at lower level. This callback uses configured globals.
|
2019-03-27 20:36:43 +01:00
|
|
|
// We deliberately include both default and explicitly specified globals
|
|
|
|
// so as the callback can access the appropriate global values regardless
|
|
|
|
// whether they are set to a default or other value.
|
2017-01-24 23:53:07 +01:00
|
|
|
if ( (config_pair.first == "renew-timer") ||
|
|
|
|
(config_pair.first == "rebind-timer") ||
|
|
|
|
(config_pair.first == "valid-lifetime") ||
|
2019-05-20 14:30:37 +02:00
|
|
|
(config_pair.first == "min-valid-lifetime") ||
|
|
|
|
(config_pair.first == "max-valid-lifetime") ||
|
2017-01-24 23:53:07 +01:00
|
|
|
(config_pair.first == "decline-probation-period") ||
|
|
|
|
(config_pair.first == "dhcp4o6-port") ||
|
|
|
|
(config_pair.first == "echo-client-id") ||
|
|
|
|
(config_pair.first == "match-client-id") ||
|
2018-10-19 16:34:29 +02:00
|
|
|
(config_pair.first == "authoritative") ||
|
2017-10-01 23:20:38 +02:00
|
|
|
(config_pair.first == "next-server") ||
|
|
|
|
(config_pair.first == "server-hostname") ||
|
2018-10-01 14:17:59 -04:00
|
|
|
(config_pair.first == "boot-file-name") ||
|
2018-11-16 23:09:31 +01:00
|
|
|
(config_pair.first == "server-tag") ||
|
2019-01-09 11:14:01 -05:00
|
|
|
(config_pair.first == "reservation-mode") ||
|
2020-10-15 12:52:51 +03:00
|
|
|
(config_pair.first == "reservations-out-of-pool") ||
|
|
|
|
(config_pair.first == "reservations-in-subnet") ||
|
|
|
|
(config_pair.first == "reservations-global") ||
|
2019-01-10 15:31:21 +01:00
|
|
|
(config_pair.first == "calculate-tee-times") ||
|
|
|
|
(config_pair.first == "t1-percent") ||
|
2019-01-07 19:42:03 +01:00
|
|
|
(config_pair.first == "t2-percent") ||
|
2020-09-25 16:48:15 +02:00
|
|
|
(config_pair.first == "cache-threshold") ||
|
2020-10-02 17:10:31 +02:00
|
|
|
(config_pair.first == "cache-max-age") ||
|
2019-06-11 02:10:18 +02:00
|
|
|
(config_pair.first == "loggers") ||
|
|
|
|
(config_pair.first == "hostname-char-set") ||
|
2019-10-03 15:11:07 -04:00
|
|
|
(config_pair.first == "hostname-char-replacement") ||
|
|
|
|
(config_pair.first == "ddns-send-updates") ||
|
|
|
|
(config_pair.first == "ddns-override-no-update") ||
|
|
|
|
(config_pair.first == "ddns-override-client-update") ||
|
|
|
|
(config_pair.first == "ddns-replace-client-name") ||
|
|
|
|
(config_pair.first == "ddns-generated-prefix") ||
|
2020-03-27 10:45:04 -04:00
|
|
|
(config_pair.first == "ddns-qualifying-suffix") ||
|
2020-10-06 15:21:25 -04:00
|
|
|
(config_pair.first == "ddns-update-on-renew") ||
|
2020-10-20 08:35:51 -04:00
|
|
|
(config_pair.first == "ddns-use-conflict-resolution") ||
|
2020-04-05 13:22:19 +02:00
|
|
|
(config_pair.first == "store-extended-info") ||
|
|
|
|
(config_pair.first == "statistic-default-sample-count") ||
|
2020-10-01 19:14:55 +02:00
|
|
|
(config_pair.first == "statistic-default-sample-age") ||
|
|
|
|
(config_pair.first == "ip-reservations-unique")) {
|
2019-03-27 11:55:10 +01:00
|
|
|
CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first,
|
|
|
|
config_pair.second);
|
2017-01-24 23:53:07 +01:00
|
|
|
continue;
|
2019-03-27 13:19:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing to configure for the user-context.
|
|
|
|
if (config_pair.first == "user-context") {
|
|
|
|
continue;
|
2017-01-24 23:53:07 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 15:00:35 +01:00
|
|
|
// If we got here, no code handled this parameter, so we bail out.
|
|
|
|
isc_throw(DhcpConfigError,
|
|
|
|
"unsupported global configuration parameter: " << config_pair.first
|
|
|
|
<< " (" << config_pair.second->getPosition() << ")");
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2020-05-22 10:34:36 +02:00
|
|
|
// Reset parameter name.
|
|
|
|
parameter_name = "<post parsing>";
|
|
|
|
|
2017-01-26 01:26:10 +01:00
|
|
|
// Apply global options in the staging config.
|
2017-01-26 15:00:35 +01:00
|
|
|
global_parser.parse(srv_cfg, mutable_cfg);
|
2017-01-26 01:26:10 +01:00
|
|
|
|
2017-09-13 00:30:32 +02:00
|
|
|
// This method conducts final sanity checks and tweaks. In particular,
|
|
|
|
// it checks that there is no conflict between plain subnets and those
|
|
|
|
// defined as part of shared networks.
|
|
|
|
global_parser.sanityChecks(srv_cfg, mutable_cfg);
|
|
|
|
|
2020-04-02 19:49:27 +03:00
|
|
|
// Validate D2 client configuration.
|
2019-06-11 02:10:18 +02:00
|
|
|
if (!d2_client_cfg) {
|
|
|
|
d2_client_cfg.reset(new D2ClientConfig());
|
|
|
|
}
|
|
|
|
d2_client_cfg->validateContents();
|
|
|
|
srv_cfg->setD2ClientConfig(d2_client_cfg);
|
|
|
|
|
2012-10-11 19:08:23 +02:00
|
|
|
} catch (const isc::Exception& ex) {
|
2013-01-21 22:01:48 +00:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
|
2020-05-22 10:34:36 +02:00
|
|
|
.arg(parameter_name).arg(ex.what());
|
2018-10-17 15:05:27 -04:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2015-01-22 11:28:13 +01:00
|
|
|
// An error occurred, so make sure that we restore original data.
|
2012-12-21 12:53:31 +01:00
|
|
|
rollback = true;
|
|
|
|
|
2012-10-11 19:08:23 +02:00
|
|
|
} catch (...) {
|
2013-05-01 07:39:08 -04:00
|
|
|
// For things like bad_cast in boost::lexical_cast
|
2020-05-22 10:34:36 +02:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(parameter_name);
|
2018-10-17 15:05:27 -04:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
|
2014-08-25 20:10:39 +02:00
|
|
|
" processing error");
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2015-01-22 11:28:13 +01:00
|
|
|
// An error occurred, so make sure that we restore original data.
|
2012-12-21 12:53:31 +01:00
|
|
|
rollback = true;
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
|
|
|
|
2017-02-13 17:34:43 +01:00
|
|
|
if (check_only) {
|
|
|
|
rollback = true;
|
|
|
|
if (!answer) {
|
2018-10-17 15:05:27 -04:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
|
2017-02-13 17:34:43 +01:00
|
|
|
"Configuration seems sane. Control-socket, hook-libraries, and D2 "
|
|
|
|
"configuration were sanity checked, but not applied.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-21 12:53:31 +01:00
|
|
|
// So far so good, there was no parsing error so let's commit the
|
|
|
|
// configuration. This will add created subnets and option values into
|
|
|
|
// the server's configuration.
|
|
|
|
// This operation should be exception safe but let's make sure.
|
|
|
|
if (!rollback) {
|
|
|
|
try {
|
2020-10-12 21:20:24 +03:00
|
|
|
|
2017-02-13 17:34:43 +01:00
|
|
|
// Setup the command channel.
|
|
|
|
configureCommandChannel();
|
|
|
|
|
2014-08-29 09:28:30 +02:00
|
|
|
// No need to commit interface names as this is handled by the
|
|
|
|
// CfgMgr::commit() function.
|
2013-08-13 13:14:38 +01:00
|
|
|
|
2017-01-11 15:22:30 -05:00
|
|
|
// Apply the staged D2ClientConfig, used to be done by parser commit
|
|
|
|
D2ClientConfigPtr cfg;
|
|
|
|
cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
|
|
|
|
CfgMgr::instance().setD2ClientConfig(cfg);
|
2017-02-24 14:38:21 +01:00
|
|
|
|
2020-04-02 19:49:27 +03:00
|
|
|
// This occurs last as if it succeeds, there is no easy way to
|
2017-02-24 14:38:21 +01:00
|
|
|
// revert it. As a result, the failure to commit a subsequent
|
|
|
|
// change causes problems when trying to roll back.
|
2020-06-25 15:29:33 +02:00
|
|
|
HooksManager::prepareUnloadLibraries();
|
|
|
|
static_cast<void>(HooksManager::unloadLibraries());
|
2017-03-04 15:42:24 +01:00
|
|
|
const HooksConfig& libraries =
|
|
|
|
CfgMgr::instance().getStagingCfg()->getHooksConfig();
|
|
|
|
libraries.loadLibraries();
|
2012-12-21 12:53:31 +01:00
|
|
|
}
|
|
|
|
catch (const isc::Exception& ex) {
|
2013-01-10 15:30:10 +00:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
|
2018-10-17 15:05:27 -04:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
|
2020-10-12 21:20:24 +03:00
|
|
|
// An error occurred, so make sure to restore the original data.
|
2012-12-21 12:53:31 +01:00
|
|
|
rollback = true;
|
|
|
|
} catch (...) {
|
2013-05-01 07:39:08 -04:00
|
|
|
// For things like bad_cast in boost::lexical_cast
|
2013-01-10 15:30:10 +00:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
|
2018-10-17 15:05:27 -04:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
|
2014-08-25 20:10:39 +02:00
|
|
|
" parsing error");
|
2020-10-12 21:20:24 +03:00
|
|
|
// An error occurred, so make sure to restore the original data.
|
2012-12-21 12:53:31 +01:00
|
|
|
rollback = true;
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
|
|
|
}
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2019-06-13 02:45:04 +02:00
|
|
|
// Moved from the commit block to add the config backend indication.
|
|
|
|
if (!rollback) {
|
|
|
|
try {
|
2020-10-12 21:20:24 +03:00
|
|
|
|
2019-06-13 02:45:04 +02:00
|
|
|
// If there are config backends, fetch and merge into staging config
|
|
|
|
server.getCBControl()->databaseConfigFetch(srv_cfg,
|
|
|
|
CBControlDHCPv4::FetchMode::FETCH_ALL);
|
|
|
|
}
|
|
|
|
catch (const isc::Exception& ex) {
|
|
|
|
std::ostringstream err;
|
|
|
|
err << "during update from config backend database: " << ex.what();
|
2019-06-27 15:45:55 +02:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(err.str());
|
2019-06-13 02:45:04 +02:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
|
2020-10-12 21:20:24 +03:00
|
|
|
// An error occurred, so make sure to restore the original data.
|
2019-06-13 02:45:04 +02:00
|
|
|
rollback = true;
|
|
|
|
} catch (...) {
|
|
|
|
// For things like bad_cast in boost::lexical_cast
|
|
|
|
std::ostringstream err;
|
|
|
|
err << "during update from config backend database: "
|
|
|
|
<< "undefined configuration parsing error";
|
2019-06-27 15:45:55 +02:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(err.str());
|
2019-06-13 02:45:04 +02:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
|
2020-10-12 21:20:24 +03:00
|
|
|
// An error occurred, so make sure to restore the original data.
|
2019-06-13 02:45:04 +02:00
|
|
|
rollback = true;
|
|
|
|
}
|
|
|
|
}
|
2018-10-10 14:51:59 -04:00
|
|
|
|
2012-12-21 12:53:31 +01:00
|
|
|
// Rollback changes as the configuration parsing failed.
|
|
|
|
if (rollback) {
|
2015-11-24 20:26:08 +01:00
|
|
|
// Revert to original configuration of runtime option definitions
|
|
|
|
// in the libdhcp++.
|
|
|
|
LibDHCP::revertRuntimeOptionDefs();
|
2012-10-11 19:08:23 +02:00
|
|
|
return (answer);
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:43:51 +02:00
|
|
|
LOG_INFO(dhcp4_logger, DHCP4_CONFIG_COMPLETE)
|
2014-10-21 11:23:53 +02:00
|
|
|
.arg(CfgMgr::instance().getStagingCfg()->
|
2014-09-15 19:27:53 +02:00
|
|
|
getConfigSummary(SrvConfig::CFGSEL_ALL4));
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2012-12-21 12:53:31 +01:00
|
|
|
// Everything was fine. Configuration is successful.
|
2018-10-17 15:05:27 -04:00
|
|
|
answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Configuration successful.");
|
2012-10-11 19:08:23 +02:00
|
|
|
return (answer);
|
|
|
|
}
|
|
|
|
|
2020-03-16 17:42:45 +02:00
|
|
|
} // namespace dhcp
|
|
|
|
} // namespace isc
|