2017-01-03 08:23:44 -05:00
|
|
|
// Copyright (C) 2012-2017 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>
|
2012-10-11 19:08:23 +02:00
|
|
|
#include <dhcp4/dhcp4_log.h>
|
2016-12-22 16:20:34 +01:00
|
|
|
#include <dhcp4/simple_parser4.h>
|
2012-12-14 12:50:23 +01:00
|
|
|
#include <dhcp/libdhcp++.h>
|
|
|
|
#include <dhcp/option_definition.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>
|
2015-11-17 13:28:40 -05:00
|
|
|
#include <dhcpsrv/parsers/client_class_def_parser.h>
|
2014-05-21 16:16:18 +02:00
|
|
|
#include <dhcp4/json_config_parser.h>
|
2014-11-26 19:23:32 +01:00
|
|
|
#include <dhcpsrv/parsers/dbaccess_parser.h>
|
|
|
|
#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>
|
2015-09-28 13:01:30 +02:00
|
|
|
#include <dhcpsrv/timer_mgr.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>
|
|
|
|
#include <boost/algorithm/string.hpp>
|
2013-04-10 17:02:10 -04:00
|
|
|
|
2012-12-11 18:07:37 +01:00
|
|
|
#include <limits>
|
2012-12-05 15:27:30 +01:00
|
|
|
#include <iostream>
|
2016-10-05 20:56:42 +02:00
|
|
|
#include <netinet/in.h>
|
2012-12-05 15:27:30 +01:00
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
|
|
|
|
2012-10-11 19:08:23 +02:00
|
|
|
using namespace std;
|
2012-12-21 12:07:43 +01:00
|
|
|
using namespace isc;
|
|
|
|
using namespace isc::dhcp;
|
2012-10-11 19:08:23 +02:00
|
|
|
using namespace isc::data;
|
|
|
|
using namespace isc::asiolink;
|
|
|
|
|
2012-12-21 12:07:43 +01:00
|
|
|
namespace {
|
|
|
|
|
2013-07-11 10:34:43 +02:00
|
|
|
/// @brief Parser for IPv4 pool definitions.
|
2013-05-01 07:39:08 -04:00
|
|
|
///
|
2013-07-11 10:34:43 +02:00
|
|
|
/// This is the IPv4 derivation of the PoolParser class and handles pool
|
|
|
|
/// definitions, i.e. a list of entries of one of two syntaxes: min-max and
|
|
|
|
/// prefix/len for IPv4 pools. Pool4 objects are created and stored in chosen
|
2013-05-01 07:39:08 -04:00
|
|
|
/// PoolStorage container.
|
2012-10-11 19:08:23 +02:00
|
|
|
///
|
2013-05-01 07:39:08 -04:00
|
|
|
/// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
|
|
|
|
class Pool4Parser : public PoolParser {
|
|
|
|
protected:
|
|
|
|
/// @brief Creates a Pool4 object given a IPv4 prefix and the prefix length.
|
2012-10-11 19:08:23 +02:00
|
|
|
///
|
2013-05-01 07:39:08 -04:00
|
|
|
/// @param addr is the IPv4 prefix of the pool.
|
|
|
|
/// @param len is the prefix length.
|
2013-07-11 10:34:43 +02:00
|
|
|
/// @param ignored dummy parameter to provide symmetry between the
|
2013-05-06 11:45:27 -04:00
|
|
|
/// PoolParser derivations. The V6 derivation requires a third value.
|
2013-07-11 10:34:43 +02:00
|
|
|
/// @return returns a PoolPtr to the new Pool4 object.
|
2013-05-06 11:45:27 -04:00
|
|
|
PoolPtr poolMaker (IOAddress &addr, uint32_t len, int32_t) {
|
2013-05-01 07:39:08 -04:00
|
|
|
return (PoolPtr(new Pool4(addr, len)));
|
|
|
|
}
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2013-05-01 07:39:08 -04:00
|
|
|
/// @brief Creates a Pool4 object given starting and ending IPv4 addresses.
|
|
|
|
///
|
|
|
|
/// @param min is the first IPv4 address in the pool.
|
|
|
|
/// @param max is the last IPv4 address in the pool.
|
2013-07-11 10:34:43 +02:00
|
|
|
/// @param ignored dummy parameter to provide symmetry between the
|
2013-05-01 07:39:08 -04:00
|
|
|
/// PoolParser derivations. The V6 derivation requires a third value.
|
2013-07-11 10:34:43 +02:00
|
|
|
/// @return returns a PoolPtr to the new Pool4 object.
|
2013-05-06 11:45:27 -04:00
|
|
|
PoolPtr poolMaker (IOAddress &min, IOAddress &max, int32_t) {
|
2013-05-01 07:39:08 -04:00
|
|
|
return (PoolPtr(new Pool4(min, max)));
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
2013-05-01 07:39:08 -04:00
|
|
|
};
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2017-01-12 01:14:50 +01:00
|
|
|
/// @brief Specialization of the pool list parser for DHCPv4
|
|
|
|
class Pools4ListParser : PoolsListParser {
|
2014-07-27 21:47:35 -04:00
|
|
|
public:
|
|
|
|
|
2017-01-12 01:14:50 +01:00
|
|
|
/// @brief parses the actual structure
|
|
|
|
///
|
|
|
|
/// This method parses the actual list of pools.
|
|
|
|
///
|
2017-01-18 00:19:44 +01:00
|
|
|
/// @param pools storage container in which to store the parsed pool.
|
2017-01-12 01:14:50 +01:00
|
|
|
/// @param pools_list a list of pool structures
|
|
|
|
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
|
2017-01-18 00:19:44 +01:00
|
|
|
void parse(PoolStoragePtr pools,
|
|
|
|
isc::data::ConstElementPtr pools_list) {
|
2017-01-12 01:14:50 +01:00
|
|
|
BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
|
2017-01-18 00:19:44 +01:00
|
|
|
Pool4Parser parser;
|
|
|
|
parser.parse(pools, pool, AF_INET);
|
2017-01-12 01:14:50 +01:00
|
|
|
}
|
2014-07-27 21:47:35 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-12-11 20:21:06 +01:00
|
|
|
/// @anchor Subnet4ConfigParser
|
2013-05-01 07:39:08 -04:00
|
|
|
/// @brief This class parses a single IPv4 subnet.
|
|
|
|
///
|
2013-07-11 10:34:43 +02:00
|
|
|
/// This is the IPv4 derivation of the SubnetConfigParser class and it parses
|
|
|
|
/// the whole subnet definition. It creates parsersfor received configuration
|
2013-05-01 07:39:08 -04:00
|
|
|
/// parameters as needed.
|
|
|
|
class Subnet4ConfigParser : public SubnetConfigParser {
|
|
|
|
public:
|
|
|
|
/// @brief Constructor
|
2012-10-11 19:08:23 +02:00
|
|
|
///
|
2015-01-22 11:28:13 +01:00
|
|
|
/// stores global scope parameters, options, option definitions.
|
2017-01-23 15:39:49 +01:00
|
|
|
Subnet4ConfigParser()
|
2017-01-27 15:41:30 +01:00
|
|
|
:SubnetConfigParser(AF_INET) {
|
2013-07-11 10:34:43 +02:00
|
|
|
}
|
2013-05-01 07:39:08 -04:00
|
|
|
|
2014-04-28 16:58:24 +02:00
|
|
|
/// @brief Parses a single IPv4 subnet configuration and adds to the
|
|
|
|
/// Configuration Manager.
|
|
|
|
///
|
|
|
|
/// @param subnet A new subnet being configured.
|
2017-01-23 15:39:49 +01:00
|
|
|
/// @return a pointer to created Subnet4 object
|
|
|
|
Subnet4Ptr parse(ConstElementPtr subnet) {
|
2017-01-12 01:14:50 +01:00
|
|
|
/// Parse Pools first.
|
|
|
|
ConstElementPtr pools = subnet->get("pools");
|
|
|
|
if (pools) {
|
2017-01-18 00:19:44 +01:00
|
|
|
Pools4ListParser parser;
|
|
|
|
parser.parse(pools_, pools);
|
2017-01-12 01:14:50 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 01:26:10 +01:00
|
|
|
SubnetPtr generic = SubnetConfigParser::parse(subnet);
|
2014-04-28 16:58:24 +02:00
|
|
|
|
2017-01-26 01:26:10 +01:00
|
|
|
if (!generic) {
|
|
|
|
isc_throw(DhcpConfigError,
|
|
|
|
"Failed to create an IPv4 subnet (" <<
|
|
|
|
subnet->getPosition() << ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
|
|
|
|
if (!sn4ptr) {
|
2017-01-23 15:39:49 +01:00
|
|
|
// If we hit this, it is a programming error.
|
|
|
|
isc_throw(Unexpected,
|
|
|
|
"Invalid Subnet4 cast in Subnet4ConfigParser::parse");
|
|
|
|
}
|
2014-01-31 20:13:58 +01:00
|
|
|
|
2017-01-23 15:39:49 +01:00
|
|
|
// Set relay information if it was parsed
|
|
|
|
if (relay_info_) {
|
2017-01-26 01:26:10 +01:00
|
|
|
sn4ptr->setRelayInfo(*relay_info_);
|
2012-12-21 12:53:31 +01:00
|
|
|
}
|
2014-11-27 15:24:08 +01:00
|
|
|
|
|
|
|
// Parse Host Reservations for this subnet if any.
|
|
|
|
ConstElementPtr reservations = subnet->get("reservations");
|
|
|
|
if (reservations) {
|
2017-01-05 21:35:11 +01:00
|
|
|
HostReservationsListParser<HostReservationParser4> parser;
|
|
|
|
parser.parse(subnet_->getID(), reservations);
|
2014-11-27 15:24:08 +01:00
|
|
|
}
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2017-01-26 01:26:10 +01:00
|
|
|
return (sn4ptr);
|
2017-01-23 15:39:49 +01:00
|
|
|
}
|
2014-04-28 16:58:24 +02:00
|
|
|
|
2013-05-01 07:39:08 -04:00
|
|
|
protected:
|
2012-12-21 12:53:31 +01:00
|
|
|
|
2013-05-01 07:39:08 -04:00
|
|
|
/// @brief Instantiates the IPv4 Subnet based on a given IPv4 address
|
2013-07-11 10:34:43 +02:00
|
|
|
/// and prefix length.
|
|
|
|
///
|
2013-05-01 07:39:08 -04:00
|
|
|
/// @param addr is IPv4 address of the subnet.
|
2013-07-11 10:34:43 +02:00
|
|
|
/// @param len is the prefix length
|
2017-01-25 14:51:11 +01:00
|
|
|
void initSubnet(isc::data::ConstElementPtr params,
|
|
|
|
isc::asiolink::IOAddress addr, uint8_t len) {
|
2014-05-27 18:55:17 +02:00
|
|
|
// The renew-timer and rebind-timer are optional. If not set, the
|
|
|
|
// option 58 and 59 will not be sent to a client. In this case the
|
|
|
|
// client will use default values based on the valid-lifetime.
|
2017-01-27 15:16:48 +01:00
|
|
|
Triplet<uint32_t> t1 = getInteger(params, "renew-timer");
|
|
|
|
Triplet<uint32_t> t2 = getInteger(params, "rebind-timer");
|
|
|
|
|
2014-05-27 18:55:17 +02:00
|
|
|
// The valid-lifetime is mandatory. It may be specified for a
|
|
|
|
// particular subnet. If not, the global value should be present.
|
|
|
|
// If there is no global value, exception is thrown.
|
2017-01-27 15:16:48 +01:00
|
|
|
Triplet<uint32_t> valid = getInteger(params, "valid-lifetime");
|
2017-01-25 14:51:11 +01:00
|
|
|
|
2014-03-26 12:40:34 +01:00
|
|
|
// Subnet ID is optional. If it is not supplied the value of 0 is used,
|
2017-01-25 14:51:11 +01:00
|
|
|
// which means autogenerate. The value was inserted earlier by calling
|
|
|
|
// SimpleParser4::setAllDefaults.
|
|
|
|
SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2014-05-27 18:55:17 +02:00
|
|
|
stringstream s;
|
|
|
|
s << addr << "/" << static_cast<int>(len) << " with params: ";
|
|
|
|
// t1 and t2 are optional may be not specified.
|
|
|
|
if (!t1.unspecified()) {
|
|
|
|
s << "t1=" << t1 << ", ";
|
|
|
|
}
|
|
|
|
if (!t2.unspecified()) {
|
|
|
|
s << "t2=" << t2 << ", ";
|
|
|
|
}
|
|
|
|
s <<"valid-lifetime=" << valid;
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2014-05-27 18:55:17 +02:00
|
|
|
LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(s.str());
|
2012-10-11 19:08:23 +02:00
|
|
|
|
2014-03-26 12:40:34 +01:00
|
|
|
Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
|
2013-10-17 19:10:50 +02:00
|
|
|
subnet_ = subnet4;
|
2013-10-11 20:03:40 +02:00
|
|
|
|
2017-01-27 15:16:48 +01:00
|
|
|
// Set the match-client-id value for the subnet. It is always present.
|
2017-01-27 17:28:53 +01:00
|
|
|
// If not explicitly specified, the default value was filled in when
|
2017-01-27 15:16:48 +01:00
|
|
|
// SimpleParser4::setAllDefaults was called.
|
|
|
|
bool match_client_id = getBoolean(params, "match-client-id");
|
|
|
|
subnet4->setMatchClientId(match_client_id);
|
2013-10-11 20:03:40 +02:00
|
|
|
|
2017-01-27 15:16:48 +01:00
|
|
|
// Set next-server. The default value is 0.0.0.0. Nevertheless, the
|
|
|
|
// user could have messed that up by specifying incorrect value.
|
|
|
|
// To avoid using 0.0.0.0, user can specify "".
|
|
|
|
string next_server;
|
2013-10-11 20:03:40 +02:00
|
|
|
try {
|
2017-01-27 15:16:48 +01:00
|
|
|
next_server = getString(params, "next-server");
|
2013-10-22 15:16:17 +02:00
|
|
|
if (!next_server.empty()) {
|
|
|
|
subnet4->setSiaddr(IOAddress(next_server));
|
|
|
|
}
|
2014-04-25 14:06:04 +02:00
|
|
|
} catch (...) {
|
2017-01-27 17:28:53 +01:00
|
|
|
ConstElementPtr next = params->get("next-server");
|
2017-01-27 21:39:45 +01:00
|
|
|
string pos;
|
2017-01-27 15:16:48 +01:00
|
|
|
if (next)
|
|
|
|
pos = next->getPosition().str();
|
2017-01-27 21:39:45 +01:00
|
|
|
else
|
|
|
|
pos = params->getPosition().str();
|
2017-01-27 15:16:48 +01:00
|
|
|
isc_throw(DhcpConfigError, "invalid parameter next-server : "
|
|
|
|
<< next_server << "(" << pos << ")");
|
2013-10-11 20:03:40 +02:00
|
|
|
}
|
2014-02-04 12:17:54 +01:00
|
|
|
|
2017-01-27 15:16:48 +01:00
|
|
|
// 4o6 specific parameter: 4o6-interface. If not explicitly specified,
|
|
|
|
// it will have the default value of "".
|
|
|
|
string iface4o6 = getString(params, "4o6-interface");
|
2015-10-31 20:33:29 +09:00
|
|
|
if (!iface4o6.empty()) {
|
2015-10-31 20:24:04 +09:00
|
|
|
subnet4->get4o6().setIface4o6(iface4o6);
|
|
|
|
subnet4->get4o6().enabled(true);
|
2015-10-31 14:08:01 +09:00
|
|
|
}
|
|
|
|
|
2017-01-27 15:16:48 +01:00
|
|
|
// 4o6 specific parameter: 4o6-subnet. If not explicitly specified, it
|
|
|
|
// will have the default value of "".
|
|
|
|
string subnet4o6 = getString(params, "4o6-subnet");
|
2015-10-31 20:33:29 +09:00
|
|
|
if (!subnet4o6.empty()) {
|
2015-10-31 14:08:01 +09:00
|
|
|
size_t slash = subnet4o6.find("/");
|
|
|
|
if (slash == std::string::npos) {
|
|
|
|
isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
|
2017-01-27 21:39:45 +01:00
|
|
|
<< subnet4o6 << ", expected format: prefix6/length");
|
2015-10-31 14:08:01 +09:00
|
|
|
}
|
|
|
|
string prefix = subnet4o6.substr(0, slash);
|
|
|
|
string lenstr = subnet4o6.substr(slash + 1);
|
|
|
|
|
|
|
|
uint8_t len = 128;
|
|
|
|
try {
|
|
|
|
len = boost::lexical_cast<unsigned int>(lenstr.c_str());
|
|
|
|
} catch (const boost::bad_lexical_cast &) {
|
|
|
|
isc_throw(DhcpConfigError, "Invalid prefix length specified in "
|
2017-01-27 21:39:45 +01:00
|
|
|
"4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value");
|
2015-10-31 14:08:01 +09:00
|
|
|
}
|
2015-10-31 20:24:04 +09:00
|
|
|
subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
|
|
|
|
subnet4->get4o6().enabled(true);
|
2015-10-31 14:08:01 +09:00
|
|
|
}
|
2014-04-25 14:06:04 +02:00
|
|
|
|
2017-01-24 23:18:58 +01:00
|
|
|
// Try 4o6 specific parameter: 4o6-interface-id
|
2017-01-27 15:16:48 +01:00
|
|
|
std::string ifaceid = getString(params, "4o6-interface-id");
|
2015-10-31 20:33:29 +09:00
|
|
|
if (!ifaceid.empty()) {
|
2015-10-31 16:47:51 +09:00
|
|
|
OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
|
|
|
|
OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
|
2015-10-31 20:24:04 +09:00
|
|
|
subnet4->get4o6().setInterfaceId(opt);
|
|
|
|
subnet4->get4o6().enabled(true);
|
2015-10-31 16:47:51 +09:00
|
|
|
}
|
2017-01-27 18:16:52 +01:00
|
|
|
|
2017-01-27 21:39:45 +01:00
|
|
|
/// client-class processing is now generic and handled in the common
|
|
|
|
/// code (see @ref isc::data::SubnetConfigParser::createSubnet)
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-05-01 07:39:08 -04:00
|
|
|
/// @brief this class parses list of DHCP4 subnets
|
2012-10-11 19:08:23 +02:00
|
|
|
///
|
|
|
|
/// This is a wrapper parser that handles the whole list of Subnet4
|
|
|
|
/// definitions. It iterates over all entries and creates Subnet4ConfigParser
|
|
|
|
/// for each entry.
|
2017-01-23 15:39:49 +01:00
|
|
|
class Subnets4ListConfigParser : public isc::data::SimpleParser {
|
2012-10-11 19:08:23 +02:00
|
|
|
public:
|
|
|
|
|
|
|
|
/// @brief parses contents of the list
|
|
|
|
///
|
2017-01-23 15:39:49 +01:00
|
|
|
/// Iterates over all entries on the list, parses its content
|
|
|
|
/// (by instantiating Subnet6ConfigParser) and adds to specified
|
|
|
|
/// configuration.
|
2012-10-11 19:08:23 +02:00
|
|
|
///
|
|
|
|
/// @param subnets_list pointer to a list of IPv4 subnets
|
2017-01-23 15:39:49 +01:00
|
|
|
/// @return number of subnets created
|
|
|
|
size_t parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
|
|
|
|
size_t cnt = 0;
|
|
|
|
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
|
|
|
|
|
|
|
|
Subnet4ConfigParser parser;
|
|
|
|
Subnet4Ptr subnet = parser.parse(subnet_json);
|
|
|
|
if (subnet) {
|
|
|
|
|
|
|
|
// Adding a subnet to the Configuration Manager may fail if the
|
|
|
|
// subnet id is invalid (duplicate). Thus, we catch exceptions
|
|
|
|
// here to append a position in the configuration string.
|
|
|
|
try {
|
|
|
|
cfg->getCfgSubnets4()->add(subnet);
|
|
|
|
cnt++;
|
|
|
|
} catch (const std::exception& ex) {
|
|
|
|
isc_throw(DhcpConfigError, ex.what() << " ("
|
|
|
|
<< subnet_json->getPosition() << ")");
|
|
|
|
}
|
|
|
|
}
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
2017-01-23 15:39:49 +01:00
|
|
|
return (cnt);
|
2012-10-11 19:08:23 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-26 21:45:23 +01:00
|
|
|
/// @brief Parser that takes care of global DHCPv4 parameters.
|
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
|
|
|
|
///
|
|
|
|
/// @throw DhcpConfigError if parameters are missing or
|
|
|
|
/// or having incorrect values.
|
2017-01-26 15:00:35 +01:00
|
|
|
void parse(SrvConfigPtr cfg, 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");
|
|
|
|
CfgMgr::instance().echoClientId(echo_client_id);
|
|
|
|
|
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.
|
|
|
|
// @todo Change for uint16_t
|
|
|
|
uint32_t dhcp4o6_port = getUint32(global, "dhcp4o6-port");
|
|
|
|
cfg->setDhcp4o6Port(dhcp4o6_port);
|
2017-01-26 01:26:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/// @brief Returns a value converted to uint32_t
|
|
|
|
///
|
2017-01-26 21:45:23 +01:00
|
|
|
/// Instantiation of getIntType() to uint32_t
|
2017-01-26 01:26:10 +01:00
|
|
|
///
|
2017-01-26 21:45:23 +01:00
|
|
|
/// @param scope specified parameter will be extracted from this scope
|
|
|
|
/// @param name name of the parameter
|
2017-01-26 01:26:10 +01:00
|
|
|
/// @return an uint32_t value
|
2017-01-26 21:45:23 +01:00
|
|
|
uint32_t getUint32(isc::data::ConstElementPtr scope,
|
|
|
|
const std::string& name) {
|
|
|
|
return (getIntType<uint32_t>(scope, name));
|
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
|
|
|
|
// data elements are't equal.
|
|
|
|
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
|
|
|
|
// close the exisitng socket and open a new socket as appropriate.
|
|
|
|
// Note that closing an existing socket means the clien will not
|
|
|
|
// 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
|
2013-05-01 07:39:08 -04:00
|
|
|
configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
2012-10-11 19:08:23 +02:00
|
|
|
if (!config_set) {
|
2012-12-05 15:27:30 +01:00
|
|
|
ConstElementPtr answer = isc::config::createAnswer(1,
|
|
|
|
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();
|
|
|
|
|
2015-09-28 13:01:30 +02:00
|
|
|
// Remove any existing timers.
|
|
|
|
TimerMgr::instance()->unregisterTimers();
|
|
|
|
|
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
|
|
|
|
// for option definitions. This is equivalent to commiting empty container.
|
|
|
|
LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
|
2015-11-24 20:26:08 +01:00
|
|
|
|
2013-07-25 12:14:42 +01:00
|
|
|
// Some of the parsers alter the state of the system in a way that can't
|
|
|
|
// easily be undone. (Or alter it in a way such that undoing the change has
|
2013-08-13 13:14:38 +01:00
|
|
|
// the same risk of failure as doing the change.)
|
2016-12-30 19:18:06 +01:00
|
|
|
HooksLibrariesParser hooks_parser;
|
2013-07-25 12:14:42 +01:00
|
|
|
|
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;
|
2013-01-18 12:05:12 +00:00
|
|
|
// config_pair holds the details of the current parser when iterating over
|
2013-01-21 20:57:57 +00:00
|
|
|
// the parsers. It is declared outside the loops so in case of an error,
|
|
|
|
// the name of the failing parser can be retrieved in the "catch" clause.
|
2013-01-18 12:05:12 +00:00
|
|
|
ConfigPair config_pair;
|
2012-10-11 19:08:23 +02:00
|
|
|
try {
|
2016-11-29 20:09:14 +01:00
|
|
|
|
2017-01-25 15:00:15 +01:00
|
|
|
SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
|
|
|
|
|
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.
|
2016-12-29 00:18:24 +01:00
|
|
|
ElementPtr mutable_cfg = boost::const_pointer_cast<Element>(config_set);
|
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);
|
|
|
|
|
2016-11-29 20:09:14 +01:00
|
|
|
// We need definitions first
|
|
|
|
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
|
|
|
if (option_defs) {
|
2016-12-22 18:43:21 +01:00
|
|
|
OptionDefListParser parser;
|
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);
|
|
|
|
}
|
|
|
|
|
2013-01-10 18:39:03 +01:00
|
|
|
// Make parsers grouping.
|
2013-01-10 18:19:21 +01:00
|
|
|
const std::map<std::string, ConstElementPtr>& values_map =
|
2016-11-29 20:09:14 +01:00
|
|
|
mutable_cfg->mapValue();
|
2013-01-21 20:57:57 +00:00
|
|
|
BOOST_FOREACH(config_pair, values_map) {
|
2016-12-27 18:58:22 +01: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
|
2017-01-03 17:12:38 +01:00
|
|
|
// with the parser code debugability, so I decided to keep it as a
|
2016-12-27 18:58:22 +01:00
|
|
|
// series of independent ifs.
|
2016-11-29 20:09:14 +01:00
|
|
|
if (config_pair.first == "option-def") {
|
|
|
|
// This is converted to SimpleParser and is handled already above.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_pair.first == "option-data") {
|
|
|
|
OptionDataListParser parser(AF_INET);
|
2017-01-10 21:33:19 +01:00
|
|
|
CfgOptionPtr cfg_option = srv_cfg->getCfgOption();
|
2016-11-29 20:09:14 +01:00
|
|
|
parser.parse(cfg_option, config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-04 13:09:28 +01:00
|
|
|
if (config_pair.first == "control-socket") {
|
|
|
|
ControlSocketParser parser;
|
|
|
|
parser.parse(*srv_cfg, config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-05 15:23:35 +01:00
|
|
|
if (config_pair.first == "host-reservation-identifiers") {
|
|
|
|
HostReservationIdsParser4 parser;
|
|
|
|
parser.parse(config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-27 18:58:22 +01:00
|
|
|
if (config_pair.first == "interfaces-config") {
|
|
|
|
IfacesConfigParser parser(AF_INET);
|
2017-01-25 15:00:15 +01:00
|
|
|
CfgIfacePtr cfg_iface = srv_cfg->getCfgIface();
|
2016-12-27 18:58:22 +01:00
|
|
|
parser.parse(cfg_iface, config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-07 07:18:40 +01:00
|
|
|
if (config_pair.first == "expired-leases-processing") {
|
|
|
|
ExpirationConfigParser parser;
|
|
|
|
parser.parse(config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-30 19:18:06 +01:00
|
|
|
if (config_pair.first == "hooks-libraries") {
|
|
|
|
hooks_parser.parse(config_pair.second);
|
|
|
|
hooks_parser.verifyLibraries();
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-23 15:39:49 +01:00
|
|
|
|
2016-12-27 18:58:22 +01:00
|
|
|
// Legacy DhcpConfigParser stuff below
|
2017-01-11 13:47:39 -05:00
|
|
|
if (config_pair.first == "dhcp-ddns") {
|
2017-01-13 18:08:14 +01:00
|
|
|
// Apply defaults if not in short cut
|
|
|
|
if (!D2ClientConfigParser::isShortCutDisabled(config_pair.second)) {
|
|
|
|
D2ClientConfigParser::setAllDefaults(config_pair.second);
|
|
|
|
}
|
2017-01-11 13:47:39 -05:00
|
|
|
D2ClientConfigParser parser;
|
|
|
|
D2ClientConfigPtr cfg = parser.parse(config_pair.second);
|
2017-01-25 15:00:15 +01:00
|
|
|
srv_cfg->setD2ClientConfig(cfg);
|
2017-01-11 13:47:39 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-08 17:12:20 +01:00
|
|
|
if (config_pair.first == "client-classes") {
|
|
|
|
ClientClassDefListParser parser;
|
2017-01-18 02:27:14 +01:00
|
|
|
ClientClassDictionaryPtr dictionary =
|
|
|
|
parser.parse(config_pair.second, AF_INET);
|
2017-01-25 15:00:15 +01:00
|
|
|
srv_cfg->setClientClassDictionary(dictionary);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-10 21:33:19 +01:00
|
|
|
// Please move at the end when migration will be finished.
|
|
|
|
if (config_pair.first == "lease-database") {
|
|
|
|
DbAccessParser parser(DbAccessParser::LEASE_DB);
|
|
|
|
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
|
|
|
|
parser.parse(cfg_db_access, config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-25 18:24:14 +01:00
|
|
|
if (config_pair.first == "hosts-database") {
|
2017-01-10 21:33:19 +01:00
|
|
|
DbAccessParser parser(DbAccessParser::HOSTS_DB);
|
|
|
|
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
|
|
|
|
parser.parse(cfg_db_access, config_pair.second);
|
2017-01-08 17:12:20 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-23 15:39:49 +01:00
|
|
|
if (config_pair.first == "subnet4") {
|
|
|
|
SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
|
|
|
|
Subnets4ListConfigParser subnets_parser;
|
|
|
|
// parse() returns number of subnets parsed. We may log it one day.
|
|
|
|
subnets_parser.parse(srv_cfg, config_pair.second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-24 23:53:07 +01:00
|
|
|
// Timers are not used in the global scope. Their values are derived
|
|
|
|
// to specific subnets (see SimpleParser6::deriveParameters).
|
|
|
|
// decline-probation-period, dhcp4o6-port, echo-client-id are
|
2017-01-26 01:26:10 +01:00
|
|
|
// handled in global_parser.parse() which sets global parameters.
|
2017-01-24 23:53:07 +01:00
|
|
|
// match-client-id is derived to subnet scope level.
|
|
|
|
if ( (config_pair.first == "renew-timer") ||
|
|
|
|
(config_pair.first == "rebind-timer") ||
|
|
|
|
(config_pair.first == "valid-lifetime") ||
|
|
|
|
(config_pair.first == "decline-probation-period") ||
|
|
|
|
(config_pair.first == "dhcp4o6-port") ||
|
|
|
|
(config_pair.first == "echo-client-id") ||
|
|
|
|
(config_pair.first == "match-client-id") ||
|
|
|
|
(config_pair.first == "next-server")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2016-12-09 16:08:24 -05:00
|
|
|
// Setup the command channel.
|
|
|
|
configureCommandChannel();
|
2015-06-03 16:32:59 +02:00
|
|
|
|
2017-01-26 01:26:10 +01:00
|
|
|
// Apply global options in the staging config.
|
|
|
|
Dhcp4ConfigParser global_parser;
|
2017-01-26 15:00:35 +01:00
|
|
|
global_parser.parse(srv_cfg, mutable_cfg);
|
2017-01-26 01:26:10 +01:00
|
|
|
|
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)
|
2013-01-18 12:05:12 +00:00
|
|
|
.arg(config_pair.first).arg(ex.what());
|
2014-08-25 20:10:39 +02:00
|
|
|
answer = isc::config::createAnswer(1, 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
|
2013-01-21 22:01:48 +00:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(config_pair.first);
|
2014-08-25 20:10:39 +02:00
|
|
|
answer = isc::config::createAnswer(1, "undefined configuration"
|
|
|
|
" 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
|
|
|
}
|
|
|
|
|
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 {
|
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
|
|
|
|
|
|
|
// This occurs last as if it succeeds, there is no easy way
|
|
|
|
// revert it. As a result, the failure to commit a subsequent
|
|
|
|
// change causes problems when trying to roll back.
|
2016-12-30 19:18:06 +01:00
|
|
|
hooks_parser.loadLibraries();
|
2017-01-11 13:47:39 -05: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);
|
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());
|
2014-08-25 20:10:39 +02:00
|
|
|
answer = isc::config::createAnswer(2, ex.what());
|
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);
|
2014-08-25 20:10:39 +02:00
|
|
|
answer = isc::config::createAnswer(2, "undefined configuration"
|
|
|
|
" parsing error");
|
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
|
|
|
|
|
|
|
// 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.
|
2014-08-25 20:10:39 +02:00
|
|
|
answer = isc::config::createAnswer(0, "Configuration successful.");
|
2012-10-11 19:08:23 +02:00
|
|
|
return (answer);
|
|
|
|
}
|
|
|
|
|
|
|
|
}; // end of isc::dhcp namespace
|
|
|
|
}; // end of isc namespace
|