2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 14:05:33 +00:00

[5315] Moved Subnet parsers from DHCP binaries to libdhcpsrv.

This commit is contained in:
Marcin Siodelski
2017-07-25 09:55:14 +02:00
committed by Tomek Mrugalski
parent 433313ef4c
commit 0a61518acf
12 changed files with 1284 additions and 666 deletions

View File

@@ -21,6 +21,7 @@
#include <dhcpsrv/parsers/host_reservation_parser.h>
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
#include <dhcpsrv/parsers/ifaces_config_parser.h>
#include <dhcpsrv/parsers/option_data_parser.h>
#include <dhcpsrv/timer_mgr.h>
#include <hooks/hooks_parser.h>
#include <config/command_mgr.h>
@@ -46,273 +47,6 @@ using namespace isc::hooks;
namespace {
/// @brief Parser for IPv4 pool definitions.
///
/// 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
/// PoolStorage container.
///
/// 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.
///
/// @param addr is the IPv4 prefix of the pool.
/// @param len is the prefix length.
/// @param ignored dummy parameter to provide symmetry between the
/// PoolParser derivations. The V6 derivation requires a third value.
/// @return returns a PoolPtr to the new Pool4 object.
PoolPtr poolMaker (IOAddress &addr, uint32_t len, int32_t) {
return (PoolPtr(new Pool4(addr, len)));
}
/// @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.
/// @param ignored dummy parameter to provide symmetry between the
/// PoolParser derivations. The V6 derivation requires a third value.
/// @return returns a PoolPtr to the new Pool4 object.
PoolPtr poolMaker (IOAddress &min, IOAddress &max, int32_t) {
return (PoolPtr(new Pool4(min, max)));
}
};
/// @brief Specialization of the pool list parser for DHCPv4
class Pools4ListParser : PoolsListParser {
public:
/// @brief parses the actual structure
///
/// This method parses the actual list of pools.
///
/// @param pools storage container in which to store the parsed pool.
/// @param pools_list a list of pool structures
/// @throw isc::dhcp::DhcpConfigError when pool parsing fails
void parse(PoolStoragePtr pools,
isc::data::ConstElementPtr pools_list) {
BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
Pool4Parser parser;
parser.parse(pools, pool, AF_INET);
}
}
};
/// @anchor Subnet4ConfigParser
/// @brief This class parses a single IPv4 subnet.
///
/// This is the IPv4 derivation of the SubnetConfigParser class and it parses
/// the whole subnet definition. It creates parsersfor received configuration
/// parameters as needed.
class Subnet4ConfigParser : public SubnetConfigParser {
public:
/// @brief Constructor
///
/// stores global scope parameters, options, option definitions.
Subnet4ConfigParser()
:SubnetConfigParser(AF_INET) {
}
/// @brief Parses a single IPv4 subnet configuration and adds to the
/// Configuration Manager.
///
/// @param subnet A new subnet being configured.
/// @return a pointer to created Subnet4 object
Subnet4Ptr parse(ConstElementPtr subnet) {
/// Parse Pools first.
ConstElementPtr pools = subnet->get("pools");
if (pools) {
Pools4ListParser parser;
parser.parse(pools_, pools);
}
SubnetPtr generic = SubnetConfigParser::parse(subnet);
if (!generic) {
isc_throw(DhcpConfigError,
"Failed to create an IPv4 subnet (" <<
subnet->getPosition() << ")");
}
Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
if (!sn4ptr) {
// If we hit this, it is a programming error.
isc_throw(Unexpected,
"Invalid Subnet4 cast in Subnet4ConfigParser::parse");
}
// Set relay information if it was parsed
if (relay_info_) {
sn4ptr->setRelayInfo(*relay_info_);
}
// Parse Host Reservations for this subnet if any.
ConstElementPtr reservations = subnet->get("reservations");
if (reservations) {
HostCollection hosts;
HostReservationsListParser<HostReservationParser4> parser;
parser.parse(subnet_->getID(), reservations, hosts);
for (auto h = hosts.begin(); h != hosts.end(); ++h) {
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(*h);
}
}
return (sn4ptr);
}
protected:
/// @brief Instantiates the IPv4 Subnet based on a given IPv4 address
/// and prefix length.
///
/// @param addr is IPv4 address of the subnet.
/// @param len is the prefix length
void initSubnet(isc::data::ConstElementPtr params,
isc::asiolink::IOAddress addr, uint8_t len) {
// 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.
Triplet<uint32_t> t1 = getInteger(params, "renew-timer");
Triplet<uint32_t> t2 = getInteger(params, "rebind-timer");
// 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.
Triplet<uint32_t> valid = getInteger(params, "valid-lifetime");
// Subnet ID is optional. If it is not supplied the value of 0 is used,
// which means autogenerate. The value was inserted earlier by calling
// SimpleParser4::setAllDefaults.
SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
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;
LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(s.str());
Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
subnet_ = subnet4;
// Set the match-client-id value for the subnet. It is always present.
// If not explicitly specified, the default value was filled in when
// SimpleParser4::setAllDefaults was called.
bool match_client_id = getBoolean(params, "match-client-id");
subnet4->setMatchClientId(match_client_id);
// 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;
try {
next_server = getString(params, "next-server");
if (!next_server.empty()) {
subnet4->setSiaddr(IOAddress(next_server));
}
} catch (...) {
ConstElementPtr next = params->get("next-server");
string pos;
if (next)
pos = next->getPosition().str();
else
pos = params->getPosition().str();
isc_throw(DhcpConfigError, "invalid parameter next-server : "
<< next_server << "(" << pos << ")");
}
// 4o6 specific parameter: 4o6-interface. If not explicitly specified,
// it will have the default value of "".
string iface4o6 = getString(params, "4o6-interface");
if (!iface4o6.empty()) {
subnet4->get4o6().setIface4o6(iface4o6);
subnet4->get4o6().enabled(true);
}
// 4o6 specific parameter: 4o6-subnet. If not explicitly specified, it
// will have the default value of "".
string subnet4o6 = getString(params, "4o6-subnet");
if (!subnet4o6.empty()) {
size_t slash = subnet4o6.find("/");
if (slash == std::string::npos) {
isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
<< subnet4o6 << ", expected format: prefix6/length");
}
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 "
"4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value");
}
subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
subnet4->get4o6().enabled(true);
}
// Try 4o6 specific parameter: 4o6-interface-id
std::string ifaceid = getString(params, "4o6-interface-id");
if (!ifaceid.empty()) {
OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
subnet4->get4o6().setInterfaceId(opt);
subnet4->get4o6().enabled(true);
}
/// client-class processing is now generic and handled in the common
/// code (see @ref isc::data::SubnetConfigParser::createSubnet)
}
};
/// @brief this class parses list of DHCP4 subnets
///
/// This is a wrapper parser that handles the whole list of Subnet4
/// definitions. It iterates over all entries and creates Subnet4ConfigParser
/// for each entry.
class Subnets4ListConfigParser : public isc::data::SimpleParser {
public:
/// @brief parses contents of the list
///
/// Iterates over all entries on the list, parses its content
/// (by instantiating Subnet6ConfigParser) and adds to specified
/// configuration.
///
/// @param subnets_list pointer to a list of IPv4 subnets
/// @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() << ")");
}
}
}
return (cnt);
}
};
/// @brief Parser that takes care of global DHCPv4 parameters.
///
/// See @ref parse method for a list of supported parameters.