mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 22:45:18 +00:00
[500-strengthen-option-def-parser] Added OptionDefParser code value sanity checks
This commit is contained in:
@@ -357,7 +357,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
|
|||||||
// We need definitions first
|
// We need definitions first
|
||||||
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
||||||
if (option_defs) {
|
if (option_defs) {
|
||||||
OptionDefListParser parser;
|
OptionDefListParser parser(AF_INET);
|
||||||
CfgOptionDefPtr cfg_option_def = srv_cfg->getCfgOptionDef();
|
CfgOptionDefPtr cfg_option_def = srv_cfg->getCfgOptionDef();
|
||||||
parser.parse(cfg_option_def, option_defs);
|
parser.parse(cfg_option_def, option_defs);
|
||||||
}
|
}
|
||||||
@@ -667,5 +667,101 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
|
|||||||
return (answer);
|
return (answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void databaseConfigFetch(const SrvConfigPtr& srv_cfg) {
|
||||||
|
|
||||||
|
ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
|
||||||
|
|
||||||
|
// Close any existing CB databasess, then open all in srv_cfg (if any)
|
||||||
|
if (!databaseConfigConnect(srv_cfg)) {
|
||||||
|
// There are no CB databases so we're done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(dhcp4_logger, DHCP4_CONFIG_FETCH);
|
||||||
|
|
||||||
|
// For now we find data based on first backend that has it.
|
||||||
|
BackendSelector backend_selector(BackendSelector::Type::UNSPEC);
|
||||||
|
|
||||||
|
// Use the server_tag if set, otherwise use ALL.
|
||||||
|
std::string server_tag = srv_cfg->getServerTag();
|
||||||
|
ServerSelector& server_selector = (server_tag.empty()? ServerSelector::ALL()
|
||||||
|
: ServerSelector::ONE(server_tag));
|
||||||
|
// Create the external config into which we'll fetch backend config data.
|
||||||
|
SrvConfigPtr external_cfg = CfgMgr::instance().createExternalCfg();
|
||||||
|
|
||||||
|
// First let's fetch the globals and add them to external config.
|
||||||
|
data::StampedValueCollection globals;
|
||||||
|
globals = mgr.getPool()->getAllGlobalParameters4(backend_selector, server_selector);
|
||||||
|
addGlobalsToConfig(external_cfg, globals);
|
||||||
|
|
||||||
|
// Now we fetch the option definitions and add them.
|
||||||
|
OptionDefContainer option_defs = mgr.getPool()->getAllOptionDefs4(backend_selector,
|
||||||
|
server_selector);
|
||||||
|
for (auto option_def = option_defs.begin(); option_def != option_defs.end(); ++option_def) {
|
||||||
|
external_cfg->getCfgOptionDef()->add((*option_def), (*option_def)->getOptionSpaceName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next fetch the options. They are returned as a container of OptionDescriptors.
|
||||||
|
OptionContainer options = mgr.getPool()->getAllOptions4(backend_selector, server_selector);
|
||||||
|
for (auto option = options.begin(); option != options.end(); ++option) {
|
||||||
|
external_cfg->getCfgOption()->add((*option), (*option).space_name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now fetch the shared networks.
|
||||||
|
SharedNetwork4Collection networks = mgr.getPool()->getAllSharedNetworks4(backend_selector,
|
||||||
|
server_selector);
|
||||||
|
for (auto network = networks.begin(); network != networks.end(); ++network) {
|
||||||
|
external_cfg->getCfgSharedNetworks4()->add((*network));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next we fetch subnets.
|
||||||
|
Subnet4Collection subnets = mgr.getPool()->getAllSubnets4(backend_selector, server_selector);
|
||||||
|
for (auto subnet = subnets.begin(); subnet != subnets.end(); ++subnet) {
|
||||||
|
external_cfg->getCfgSubnets4()->add((*subnet));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we merge the fecthed configuration into the staging configuration.
|
||||||
|
CfgMgr::instance().mergeIntoStagingCfg(external_cfg->getSequence());
|
||||||
|
LOG_INFO(dhcp4_logger, DHCP4_CONFIG_MERGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool databaseConfigConnect(const SrvConfigPtr& srv_cfg) {
|
||||||
|
// We need to get rid of any existing backends. These would be any
|
||||||
|
// opened by previous configuration cycle.
|
||||||
|
ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
|
||||||
|
mgr.delAllBackends();
|
||||||
|
|
||||||
|
// Fetch the config-control info.
|
||||||
|
ConstConfigControlInfoPtr config_ctl = srv_cfg->getConfigControlInfo();
|
||||||
|
if (!config_ctl || config_ctl->getConfigDatabases().empty()) {
|
||||||
|
// No config dbs, nothing to do.
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the configured DBs and instantiate them.
|
||||||
|
for (auto db : config_ctl->getConfigDatabases()) {
|
||||||
|
LOG_INFO(dhcp4_logger, DHCP4_OPEN_CONFIG_DB)
|
||||||
|
.arg(db.redactedAccessString());
|
||||||
|
mgr.addBackend(db.getAccessString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the caller know we have opened DBs.
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addGlobalsToConfig(SrvConfigPtr external_cfg, data::StampedValueCollection& cb_globals) {
|
||||||
|
const auto& index = cb_globals.get<StampedValueNameIndexTag>();
|
||||||
|
for (auto cb_global = index.begin(); cb_global != index.end(); ++cb_global) {
|
||||||
|
|
||||||
|
if ((*cb_global)->amNull()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
external_cfg->addConfiguredGlobal((*cb_global)->getName(),
|
||||||
|
(*cb_global)->getElementValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}; // end of isc::dhcp namespace
|
}; // end of isc::dhcp namespace
|
||||||
}; // end of isc namespace
|
}; // end of isc namespace
|
||||||
|
@@ -464,7 +464,7 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
|
|||||||
// We need definitions first
|
// We need definitions first
|
||||||
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
||||||
if (option_defs) {
|
if (option_defs) {
|
||||||
OptionDefListParser parser;
|
OptionDefListParser parser(AF_INET6);
|
||||||
CfgOptionDefPtr cfg_option_def = srv_config->getCfgOptionDef();
|
CfgOptionDefPtr cfg_option_def = srv_config->getCfgOptionDef();
|
||||||
parser.parse(cfg_option_def, option_defs);
|
parser.parse(cfg_option_def, option_defs);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
|
// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
// 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
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -108,10 +108,10 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
|
|||||||
SimpleParser4::OPTION4_DEF_DEFAULTS :
|
SimpleParser4::OPTION4_DEF_DEFAULTS :
|
||||||
SimpleParser6::OPTION6_DEF_DEFAULTS);
|
SimpleParser6::OPTION6_DEF_DEFAULTS);
|
||||||
|
|
||||||
OptionDefParser parser;
|
OptionDefParser parser(family);
|
||||||
BOOST_FOREACH(ConstElementPtr option_def, option_defs->listValue()) {
|
BOOST_FOREACH(ConstElementPtr option_def, option_defs->listValue()) {
|
||||||
OptionDefinitionTuple def;
|
OptionDefinitionTuple def;
|
||||||
|
|
||||||
def = parser.parse(option_def);
|
def = parser.parse(option_def);
|
||||||
// Verify if the defition is for an option which are
|
// Verify if the defition is for an option which are
|
||||||
// in a deferred processing list.
|
// in a deferred processing list.
|
||||||
|
@@ -111,12 +111,16 @@ OptionDataParser::findOptionDefinition(const std::string& option_space,
|
|||||||
|
|
||||||
// ******************************** OptionDefParser ****************************
|
// ******************************** OptionDefParser ****************************
|
||||||
|
|
||||||
|
OptionDefParser::OptionDefParser(const uint16_t address_family)
|
||||||
|
: address_family_(address_family) {
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<isc::dhcp::OptionDefinitionPtr, std::string>
|
std::pair<isc::dhcp::OptionDefinitionPtr, std::string>
|
||||||
OptionDefParser::parse(ConstElementPtr option_def) {
|
OptionDefParser::parse(ConstElementPtr option_def) {
|
||||||
|
|
||||||
// Get mandatory parameters.
|
// Get mandatory parameters.
|
||||||
std::string name = getString(option_def, "name");
|
std::string name = getString(option_def, "name");
|
||||||
uint32_t code = getInteger(option_def, "code");
|
int64_t code64 = getInteger(option_def, "code");
|
||||||
std::string type = getString(option_def, "type");
|
std::string type = getString(option_def, "type");
|
||||||
|
|
||||||
// Get optional parameters. Whoever called this parser, should have
|
// Get optional parameters. Whoever called this parser, should have
|
||||||
@@ -127,6 +131,29 @@ OptionDefParser::parse(ConstElementPtr option_def) {
|
|||||||
std::string encapsulates = getString(option_def, "encapsulate");
|
std::string encapsulates = getString(option_def, "encapsulate");
|
||||||
ConstElementPtr user_context = option_def->get("user-context");
|
ConstElementPtr user_context = option_def->get("user-context");
|
||||||
|
|
||||||
|
// Check code value.
|
||||||
|
if (code64 < 0) {
|
||||||
|
isc_throw(DhcpConfigError, "option code must not be negative "
|
||||||
|
"(" << getPosition("code", option_def) << ")");
|
||||||
|
} else if (code64 == 0) {
|
||||||
|
isc_throw(DhcpConfigError, "option code must not be zero "
|
||||||
|
"(" << getPosition("code", option_def) << ")");
|
||||||
|
} else if (address_family_ == AF_INET &&
|
||||||
|
code64 > std::numeric_limits<uint8_t>::max()) {
|
||||||
|
isc_throw(DhcpConfigError, "invalid option code '" << code64
|
||||||
|
<< "', it must not be greater than '"
|
||||||
|
<< static_cast<int>(std::numeric_limits<uint8_t>::max())
|
||||||
|
<< "' (" << getPosition("code", option_def) << ")");
|
||||||
|
} else if (address_family_ == AF_INET6 &&
|
||||||
|
code64 > std::numeric_limits<uint16_t>::max()) {
|
||||||
|
isc_throw(DhcpConfigError, "invalid option code '" << code64
|
||||||
|
<< "', it must not be greater than '"
|
||||||
|
<< std::numeric_limits<uint16_t>::max()
|
||||||
|
<< "' (" << getPosition("code", option_def) << ")");
|
||||||
|
}
|
||||||
|
uint32_t code = static_cast<uint32_t>(code64);
|
||||||
|
|
||||||
|
// Validate space name.
|
||||||
if (!OptionSpace::validateName(space)) {
|
if (!OptionSpace::validateName(space)) {
|
||||||
isc_throw(DhcpConfigError, "invalid option space name '"
|
isc_throw(DhcpConfigError, "invalid option space name '"
|
||||||
<< space << "' ("
|
<< space << "' ("
|
||||||
@@ -198,6 +225,11 @@ OptionDefParser::parse(ConstElementPtr option_def) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ******************************** OptionDefListParser ************************
|
// ******************************** OptionDefListParser ************************
|
||||||
|
|
||||||
|
OptionDefListParser::OptionDefListParser(const uint16_t address_family)
|
||||||
|
: address_family_(address_family) {
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OptionDefListParser::parse(CfgOptionDefPtr storage, ConstElementPtr option_def_list) {
|
OptionDefListParser::parse(CfgOptionDefPtr storage, ConstElementPtr option_def_list) {
|
||||||
if (!option_def_list) {
|
if (!option_def_list) {
|
||||||
@@ -207,7 +239,7 @@ OptionDefListParser::parse(CfgOptionDefPtr storage, ConstElementPtr option_def_l
|
|||||||
<< option_def_list->getPosition() << ")");
|
<< option_def_list->getPosition() << ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionDefParser parser;
|
OptionDefParser parser(address_family_);
|
||||||
BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
|
BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
|
||||||
OptionDefinitionTuple def;
|
OptionDefinitionTuple def;
|
||||||
|
|
||||||
|
@@ -228,6 +228,11 @@ typedef std::pair<isc::dhcp::OptionDefinitionPtr, std::string> OptionDefinitionT
|
|||||||
/// This parser creates an instance of a single option definition.
|
/// This parser creates an instance of a single option definition.
|
||||||
class OptionDefParser : public isc::data::SimpleParser {
|
class OptionDefParser : public isc::data::SimpleParser {
|
||||||
public:
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
///
|
||||||
|
/// @param address_family Address family: @c AF_INET or @c AF_INET6.
|
||||||
|
OptionDefParser(const uint16_t address_family);
|
||||||
|
|
||||||
/// @brief Parses an entry that describes single option definition.
|
/// @brief Parses an entry that describes single option definition.
|
||||||
///
|
///
|
||||||
/// @param option_def a configuration entry to be parsed.
|
/// @param option_def a configuration entry to be parsed.
|
||||||
@@ -236,6 +241,10 @@ public:
|
|||||||
/// @throw DhcpConfigError if parsing was unsuccessful.
|
/// @throw DhcpConfigError if parsing was unsuccessful.
|
||||||
OptionDefinitionTuple
|
OptionDefinitionTuple
|
||||||
parse(isc::data::ConstElementPtr option_def);
|
parse(isc::data::ConstElementPtr option_def);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief Address family: @c AF_INET or @c AF_INET6.
|
||||||
|
uint16_t address_family_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Parser for a list of option definitions.
|
/// @brief Parser for a list of option definitions.
|
||||||
@@ -246,6 +255,11 @@ public:
|
|||||||
/// is put into the provided storage.
|
/// is put into the provided storage.
|
||||||
class OptionDefListParser : public isc::data::SimpleParser {
|
class OptionDefListParser : public isc::data::SimpleParser {
|
||||||
public:
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
///
|
||||||
|
/// @param address_family Address family: @c AF_INET or @c AF_INET6.
|
||||||
|
OptionDefListParser(const uint16_t address_family);
|
||||||
|
|
||||||
/// @brief Parses a list of option definitions, create them and store in cfg
|
/// @brief Parses a list of option definitions, create them and store in cfg
|
||||||
///
|
///
|
||||||
/// This method iterates over def_list, which is a JSON list of option definitions,
|
/// This method iterates over def_list, which is a JSON list of option definitions,
|
||||||
@@ -255,6 +269,10 @@ public:
|
|||||||
/// @param def_list JSON list describing option definitions
|
/// @param def_list JSON list describing option definitions
|
||||||
/// @param cfg parsed option definitions will be stored here
|
/// @param cfg parsed option definitions will be stored here
|
||||||
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list);
|
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief Address family: @c AF_INET or @c AF_INET6.
|
||||||
|
uint16_t address_family_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief a collection of pools
|
/// @brief a collection of pools
|
||||||
@@ -421,7 +439,7 @@ public:
|
|||||||
/// @throw isc::dhcp::DhcpConfigError if the address string is not a valid
|
/// @throw isc::dhcp::DhcpConfigError if the address string is not a valid
|
||||||
/// IP address, is an address of the wrong family, or is already in the
|
/// IP address, is an address of the wrong family, or is already in the
|
||||||
/// relay address list
|
/// relay address list
|
||||||
void addAddress(const std::string& name, const std::string& address_str,
|
void addAddress(const std::string& name, const std::string& address_str,
|
||||||
isc::data::ConstElementPtr relay_elem,
|
isc::data::ConstElementPtr relay_elem,
|
||||||
const isc::dhcp::Network::RelayInfoPtr& relay_info);
|
const isc::dhcp::Network::RelayInfoPtr& relay_info);
|
||||||
private:
|
private:
|
||||||
|
@@ -233,7 +233,7 @@ public:
|
|||||||
if (def_config != values_map.end()) {
|
if (def_config != values_map.end()) {
|
||||||
|
|
||||||
CfgOptionDefPtr cfg_def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef();
|
CfgOptionDefPtr cfg_def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef();
|
||||||
OptionDefListParser def_list_parser;
|
OptionDefListParser def_list_parser(family_);
|
||||||
def_list_parser.parse(cfg_def, def_config->second);
|
def_list_parser.parse(cfg_def, def_config->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,6 +717,73 @@ TEST_F(ParseConfigTest, defaultSpaceOptionDefTest) {
|
|||||||
cfg.runCfgOptionsTest(family_, config);
|
cfg.runCfgOptionsTest(family_, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Check parsing of option definitions using invalid code fails.
|
||||||
|
TEST_F(ParseConfigTest, badCodeOptionDefTest) {
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
SCOPED_TRACE("negative code");
|
||||||
|
std::string config =
|
||||||
|
"{ \"option-def\": [ {"
|
||||||
|
" \"name\": \"negative\","
|
||||||
|
" \"code\": -1,"
|
||||||
|
" \"type\": \"ipv6-address\","
|
||||||
|
" \"space\": \"isc\""
|
||||||
|
" } ]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
int rcode = parseConfiguration(config, true);
|
||||||
|
ASSERT_NE(0, rcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SCOPED_TRACE("zero code");
|
||||||
|
std::string config =
|
||||||
|
"{ \"option-def\": [ {"
|
||||||
|
" \"name\": \"zero\","
|
||||||
|
" \"code\": 0,"
|
||||||
|
" \"type\": \"ipv6-address\","
|
||||||
|
" \"space\": \"isc\""
|
||||||
|
" } ]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
int rcode = parseConfiguration(config, true);
|
||||||
|
ASSERT_NE(0, rcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SCOPED_TRACE("out of range code (v6)");
|
||||||
|
std::string config =
|
||||||
|
"{ \"option-def\": [ {"
|
||||||
|
" \"name\": \"hundred-thousands\","
|
||||||
|
" \"code\": 100000,"
|
||||||
|
" \"type\": \"ipv6-address\","
|
||||||
|
" \"space\": \"isc\""
|
||||||
|
" } ]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
int rcode = parseConfiguration(config, true);
|
||||||
|
ASSERT_NE(0, rcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SCOPED_TRACE("out of range code (v4)");
|
||||||
|
family_ = AF_INET; // Switch to DHCPv4.
|
||||||
|
|
||||||
|
std::string config =
|
||||||
|
"{ \"option-def\": [ {"
|
||||||
|
" \"name\": \"thousand\","
|
||||||
|
" \"code\": 1000,"
|
||||||
|
" \"type\": \"ip-address\","
|
||||||
|
" \"space\": \"isc\""
|
||||||
|
" } ]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
int rcode = parseConfiguration(config, false);
|
||||||
|
ASSERT_NE(0, rcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Check parsing of option definitions using invalid space fails.
|
/// @brief Check parsing of option definitions using invalid space fails.
|
||||||
TEST_F(ParseConfigTest, badSpaceOptionDefTest) {
|
TEST_F(ParseConfigTest, badSpaceOptionDefTest) {
|
||||||
|
|
||||||
@@ -724,7 +791,7 @@ TEST_F(ParseConfigTest, badSpaceOptionDefTest) {
|
|||||||
std::string config =
|
std::string config =
|
||||||
"{ \"option-def\": [ {"
|
"{ \"option-def\": [ {"
|
||||||
" \"name\": \"foo\","
|
" \"name\": \"foo\","
|
||||||
" \"code\": 100000,"
|
" \"code\": 100,"
|
||||||
" \"type\": \"ipv6-address\","
|
" \"type\": \"ipv6-address\","
|
||||||
" \"space\": \"-1\""
|
" \"space\": \"-1\""
|
||||||
" } ]"
|
" } ]"
|
||||||
|
Reference in New Issue
Block a user