Commit a2329d17 authored by Marcin Siodelski's avatar Marcin Siodelski

[3874] Added DUID configuration parser.

parent fe5f2029
......@@ -139,6 +139,8 @@ libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.cc
libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.h
libkea_dhcpsrv_la_SOURCES += parsers/duid_config_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/duid_config_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.cc
......
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <cc/data.h>
#include <dhcp/duid.h>
#include <dhcpsrv/cfg_duid.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/parsers/duid_config_parser.h>
#include <exceptions/exceptions.h>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <limits>
#include <string>
using namespace isc::data;
namespace isc {
namespace dhcp {
DUIDConfigParser::DUIDConfigParser()
: DhcpConfigParser() {
}
void
DUIDConfigParser::build(isc::data::ConstElementPtr duid_configuration) {
bool type_present = false;
BOOST_FOREACH(ConfigPair element, duid_configuration->mapValue()) {
try {
if (element.first == "type") {
type_present = true;
setType(element.second->stringValue());
} else if (element.first == "identifier") {
setIdentifier(element.second->stringValue());
} else if (element.first == "htype") {
setHType(element.second->intValue());
} else if (element.first == "time") {
setTime(element.second->intValue());
} else if (element.first == "enterprise-id") {
setEnterpriseId(element.second->intValue());
} else {
isc_throw(DhcpConfigError, "unsupported configuration "
"parameter '" << element.first << "'");
}
} catch (const std::exception& ex) {
// Append position.
isc_throw(DhcpConfigError, ex.what() << " ("
<< element.second->getPosition() << ")");
}
}
// "type" is mandatory
if (!type_present) {
isc_throw(DhcpConfigError, "mandatory parameter \"type\" not specified"
" for the DUID configuration ("
<< duid_configuration->getPosition() << ")");
}
}
void
DUIDConfigParser::setType(const std::string& duid_type) const {
// Map DUID type represented as text into numeric value.
DUID::DUIDType numeric_type = DUID::DUID_UNKNOWN;
if (duid_type == "LLT") {
numeric_type = DUID::DUID_LLT;
} else if (duid_type == "EN") {
numeric_type = DUID::DUID_EN;
} else if (duid_type == "LL") {
numeric_type = DUID::DUID_LL;
} else {
isc_throw(DhcpConfigError, "unsupported DUID type '"
<< duid_type << "'. Expected: LLT, EN or LL");
}
const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
cfg->setType(static_cast<DUID::DUIDType>(numeric_type));
}
void
DUIDConfigParser::setIdentifier(const std::string& identifier) const {
const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
cfg->setIdentifier(identifier);
}
void
DUIDConfigParser::setHType(const int64_t htype) const {
const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
checkRange<uint16_t>("htype", htype);
cfg->setHType(static_cast<uint16_t>(htype));
}
void
DUIDConfigParser::setTime(const int64_t new_time) const {
const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
checkRange<uint32_t>("time", new_time);
cfg->setTime(static_cast<uint32_t>(new_time));
}
void
DUIDConfigParser::setEnterpriseId(const int64_t enterprise_id) const {
const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
checkRange<uint32_t>("enterprise-id", enterprise_id);
cfg->setEnterpriseId(static_cast<uint32_t>(enterprise_id));
}
template<typename NumericType>
void
DUIDConfigParser::checkRange(const std::string& parameter_name,
const int64_t parameter_value) const {
if ((parameter_value < 0) ||
(parameter_value > std::numeric_limits<NumericType>::max())) {
isc_throw(DhcpConfigError, "out of range value '" << parameter_value
<< "' specified for parameter '" << parameter_name
<< "'; expected value in range of [0.."
<< std::numeric_limits<NumericType>::max() << "]");
}
}
} // end of namespace isc::dhcp
} // end of namespace isc
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DUID_CONFIG_PARSER_H
#define DUID_CONFIG_PARSER_H
#include <cc/data.h>
#include <dhcpsrv/parsers/dhcp_config_parser.h>
#include <stdint.h>
#include <string>
namespace isc {
namespace dhcp {
/// @brief Parser for a single host reservation entry.
class DUIDConfigParser : public DhcpConfigParser {
public:
/// @brief Constructor.
DUIDConfigParser();
/// @brief Parses DUID configuration.
///
/// @param duid_configuration Data element holding a map representing
/// DUID configuration.
///
/// @throw DhcpConfigError If the configuration is invalid.
virtual void build(isc::data::ConstElementPtr duid_configuration);
/// @brief Commit, unused.
virtual void commit() { }
private:
/// @brief Validate and set DUID type.
///
/// @param duid_type DUID type in textfual format.
void setType(const std::string& duid_type) const;
/// @brief Validate and set identifier.
///
/// @param identifier Identifier.
void setIdentifier(const std::string& identifier) const;
/// @brief Validate and set hardware type.
///
/// @param htype Hardware type.
void setHType(const int64_t htype) const;
/// @brief Validate and set time value.
///
/// @param new_time Time value to be used for DUID.
void setTime(const int64_t new_time) const;
/// @brief Validate and set enterprise id.
///
/// @param enterprise_id Enterprise id.
void setEnterpriseId(const int64_t enterprise_id) const;
/// @brief Verifies if the specified parameter is in range.
///
/// Each numeric value must be in range of [0 .. max_value], where
/// max_value is a maximum value for the numeric type used for this
/// parameter.
///
/// @param parameter_name Parameter name.
/// @tparam Numeric type of the specified parameter.
template<typename NumericType>
void checkRange(const std::string& parameter_name,
const int64_t parameter_value) const;
};
}
} // end of namespace isc
#endif // DUID_CONFIG_PARSER_H
......@@ -84,6 +84,7 @@ libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc
libdhcpsrv_unittests_SOURCES += daemon_unittest.cc
libdhcpsrv_unittests_SOURCES += database_connection_unittest.cc
libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += host_unittest.cc
......
......@@ -93,6 +93,8 @@ TEST(CfgDUIDTest, setIdentifier) {
<< toString(cfg_duid.getIdentifier());
}
// This test verifies that the invalid identifier is rejected and
// exception is thrown.
TEST(CfgDUIDTest, setInvalidIdentifier) {
CfgDUID cfg_duid;
// Check that hexadecimal characters may be lower case.
......
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <cc/data.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/cfg_duid.h>
#include <dhcpsrv/parsers/duid_config_parser.h>
#include <dhcpsrv/testutils/config_result_check.h>
#include <util/encode/hex.h>
#include <gtest/gtest.h>
#include <limits>
#include <sstream>
#include <string>
using namespace isc;
using namespace isc::data;
using namespace isc::dhcp;
namespace {
/// @brief Test fixture class for @c DUIDConfigParser
class DUIDConfigParserTest : public ::testing::Test {
public:
/// @brief Creates simple configuration with DUID type only.
///
/// @param duid_type DUID type in the textual format.
std::string createConfigWithType(const std::string& duid_type) const;
/// @brief Creates simple configuration with DUID type and one
/// numeric parameter.
///
/// @param name Parameter name.
/// @param value Parameter value.
std::string createConfigWithInteger(const std::string& name,
const int64_t value) const;
/// @brief Parse configuration.
///
/// @param config String representing DUID configuration.
void build(const std::string& config) const;
/// @brief Test that only a DUID type can be specified.
///
/// @param duid_type DUID type in numeric format.
/// @param duid_type_text DUID type in textual format.
void testTypeOnly(const DUID::DUIDType& duid_type,
const std::string duid_type_text) const;
/// @brief Test that invalid configuration is rejected.
///
/// @param config Holds JSON configuration to be used.
void testInvalidConfig(const std::string& config) const;
/// @brief Test out of range numeric values.
///
/// @param param_name Parameter name.
/// @tparam Type of the numeric parameter.
template<typename NumericType>
void testOutOfRange(const std::string& param_name) {
// Obtain maximum value for the specified numeric type.
const uint64_t max_value = std::numeric_limits<NumericType>::max();
// Negative values are not allowed.
EXPECT_THROW(build(createConfigWithInteger(param_name, -1)),
DhcpConfigError);
// Zero is allowed.
EXPECT_NO_THROW(build(createConfigWithInteger(param_name, 0)));
// Maximum value.
EXPECT_NO_THROW(build(createConfigWithInteger(param_name, max_value)));
// Value greater than maximum should result in exception.
EXPECT_THROW(build(createConfigWithInteger(param_name, max_value + 1)),
DhcpConfigError);
}
/// @brief Converts vector to string of hexadecimal digits.
///
/// @param vec Input vector.
/// @return String of hexadecimal digits converted from vector.
std::string toString(const std::vector<uint8_t>& vec) const;
};
std::string
DUIDConfigParserTest::createConfigWithType(const std::string& duid_type) const {
std::ostringstream s;
s << "{ \"type\": \"" << duid_type << "\" }";
return (s.str());
}
std::string
DUIDConfigParserTest::createConfigWithInteger(const std::string& name,
const int64_t value) const {
std::ostringstream s;
s << "{ \"type\": \"LLT\", \"" << name << "\": " << value << " }";
return (s.str());
}
void
DUIDConfigParserTest::build(const std::string& config) const {
ElementPtr config_element = Element::fromJSON(config);
DUIDConfigParser parser;
parser.build(config_element);
}
void
DUIDConfigParserTest::testTypeOnly(const DUID::DUIDType& duid_type,
const std::string duid_type_text) const {
// Use DUID configuration with only a "type".
ASSERT_NO_THROW(build(createConfigWithType(duid_type_text)));
// Make sure that the type is correct and that other parameters are set
// to their defaults.
CfgDUIDPtr cfg_duid = CfgMgr::instance().getStagingCfg()->getCfgDUID();
EXPECT_EQ(duid_type, cfg_duid->getType());
EXPECT_TRUE(cfg_duid->getIdentifier().empty());
EXPECT_EQ(0, cfg_duid->getHType());
EXPECT_EQ(0, cfg_duid->getTime());
EXPECT_EQ(0, cfg_duid->getEnterpriseId());
}
void
DUIDConfigParserTest::testInvalidConfig(const std::string& config) const {
EXPECT_THROW(build(config), DhcpConfigError);
}
std::string
DUIDConfigParserTest::toString(const std::vector<uint8_t>& vec) const {
try {
return (util::encode::encodeHex(vec));
} catch (...) {
ADD_FAILURE() << "toString: unable to encode vector to"
" hexadecimal string";
}
return ("");
}
// This test verifies that it is allowed to specify a DUID-LLT type.
TEST_F(DUIDConfigParserTest, typeOnlyLLT) {
testTypeOnly(DUID::DUID_LLT, "LLT");
}
// This test verifies that it is allowed to specify a DUID-EN type.
TEST_F(DUIDConfigParserTest, typeOnlyEN) {
testTypeOnly(DUID::DUID_EN, "EN");
}
// This test verifies that it is allowed to specify a DUID-LL type.
TEST_F(DUIDConfigParserTest, typeOnlyLL) {
testTypeOnly(DUID::DUID_LL, "LL");
}
// This test verifies that using unsupported DUID type will result in
// configuration error.
TEST_F(DUIDConfigParserTest, typeInvalid) {
testInvalidConfig(createConfigWithType("WRONG"));
}
// This test verifies that DUID type is required.
TEST_F(DUIDConfigParserTest, noType) {
// First check that the configuration with DUID type specified is
// accepted.
ASSERT_NO_THROW(build("{ \"type\": \"LLT\", \"time\": 1 }"));
// Now remove the type and expect an error.
testInvalidConfig("{ \"time\": 1 }");
}
// This test verifies that all parameters can be set.
TEST_F(DUIDConfigParserTest, allParameters) {
// Set all parameters.
ASSERT_NO_THROW(build("{ \"type\": \"EN\","
" \"identifier\": \"ABCDEF\","
" \"time\": 100,"
" \"htype\": 8,"
" \"enterprise-id\": 2024"
"}"));
// Verify that parameters have been set correctly.
CfgDUIDPtr cfg_duid = CfgMgr::instance().getStagingCfg()->getCfgDUID();
EXPECT_EQ(DUID::DUID_EN, cfg_duid->getType());
EXPECT_EQ("ABCDEF", toString(cfg_duid->getIdentifier()));
EXPECT_EQ(8, cfg_duid->getHType());
EXPECT_EQ(100, cfg_duid->getTime());
EXPECT_EQ(2024, cfg_duid->getEnterpriseId());
}
// Test out of range values for time.
TEST_F(DUIDConfigParserTest, timeOutOfRange) {
testOutOfRange<uint32_t>("time");
}
// Test out of range values for hardware type.
TEST_F(DUIDConfigParserTest, htypeOutOfRange) {
testOutOfRange<uint16_t>("htype");
}
// Test out of range values for enterprise id.
TEST_F(DUIDConfigParserTest, enterpriseIdOutOfRange) {
testOutOfRange<uint32_t>("enterprise-id");
}
} // end of anonymous namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment