Commit 8390f9de authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[5110_fix] re-applying patch made on trac5110

parent 9eadd3f9
......@@ -64,7 +64,10 @@ libd2_la_SOURCES += d2_log.cc d2_log.h
libd2_la_SOURCES += d2_process.cc d2_process.h
libd2_la_SOURCES += d2_config.cc d2_config.h
libd2_la_SOURCES += d2_cfg_mgr.cc d2_cfg_mgr.h
libd2_la_SOURCES += d2_lexer.ll location.hh position.hh stack.hh
libd2_la_SOURCES += d2_parser.cc d2_parser.h
libd2_la_SOURCES += d2_queue_mgr.cc d2_queue_mgr.h
libd2_la_SOURCES += d2_simple_parser.cc d2_simple_parser.h
libd2_la_SOURCES += d2_update_message.cc d2_update_message.h
libd2_la_SOURCES += d2_update_mgr.cc d2_update_mgr.h
libd2_la_SOURCES += d2_zone.cc d2_zone.h
......@@ -73,6 +76,7 @@ libd2_la_SOURCES += nc_add.cc nc_add.h
libd2_la_SOURCES += nc_remove.cc nc_remove.h
libd2_la_SOURCES += nc_trans.cc nc_trans.h
libd2_la_SOURCES += d2_controller.cc d2_controller.h
libd2_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h
nodist_libd2_la_SOURCES = d2_messages.h d2_messages.cc
EXTRA_DIST += d2_messages.mes
......@@ -115,3 +119,31 @@ endif
kea_dhcp_ddnsdir = $(pkgdatadir)
kea_dhcp_ddns_DATA = dhcp-ddns.spec
if GENERATE_PARSER
parser: d2_lexer.cc location.hh position.hh stack.hh d2_parser.cc d2_parser.h
@echo "Flex/bison files regenerated"
# --- Flex/Bison stuff below --------------------------------------------------
# When debugging grammar issues, it's useful to add -v to bison parameters.
# bison will generate parser.output file that explains the whole grammar.
# It can be used to manually follow what's going on in the parser.
# This is especially useful if yydebug_ is set to 1 as that variable
# will cause parser to print out its internal state.
# Call flex with -s to check that the default rule can be suppressed
# Call bison with -W to get warnings like unmarked empty rules
# Note C++11 deprecated register still used by flex < 2.6.0
location.hh position.hh stack.hh d2_parser.cc d2_parser.h: d2_parser.yy
$(YACC) --defines=d2_parser.h --report=all --report-file=d2_parser.report -o d2_parser.cc d2_parser.yy
d2_lexer.cc: d2_lexer.ll
$(LEX) --prefix d2_parser_ -o d2_lexer.cc d2_lexer.ll
else
parser location.hh position.hh stack.hh d2_parser.cc d2_parser.h d2_lexer.cc:
@echo Parser generation disabled. Configure with --enable-generate-parser to enable it.
endif
......@@ -8,6 +8,7 @@
#include <d2/d2_log.h>
#include <d2/d2_cfg_mgr.h>
#include <d2/d2_simple_parser.h>
#include <util/encode/hex.h>
#include <boost/foreach.hpp>
......@@ -197,96 +198,164 @@ D2CfgMgr::getConfigSummary(const uint32_t) {
return (getD2Params()->getConfigSummary());
}
void
D2CfgMgr::buildParams(isc::data::ConstElementPtr params_config) {
// Base class build creates parses and invokes build on each parser.
// This populate the context scalar stores with all of the parameters.
DCfgMgrBase::buildParams(params_config);
// Fetch and validate the parameters from the context to create D2Params.
// We validate them here rather than just relying on D2Param constructor
// so we can spit out config text position info with errors.
namespace {
// Fetch and validate ip_address.
D2CfgContextPtr context = getD2CfgContext();
isc::dhcp::StringStoragePtr strings = context->getStringStorage();
asiolink::IOAddress ip_address(D2Params::DFT_IP_ADDRESS);
template <typename int_type> int_type
getInt(const std::string& name, isc::data::ConstElementPtr value) {
int64_t val_int = value->intValue();
if ((val_int < std::numeric_limits<int_type>::min()) ||
(val_int > std::numeric_limits<int_type>::max())) {
isc_throw(D2CfgError, "out of range value (" << val_int
<< ") specified for parameter '" << name
<< "' (" << value->getPosition() << ")");
}
return (static_cast<int_type>(val_int));
}
std::string ip_address_str = strings->getOptionalParam("ip-address",
D2Params::
DFT_IP_ADDRESS);
isc::asiolink::IOAddress
getIOAddress(const std::string& name, isc::data::ConstElementPtr value) {
std::string str = value->stringValue();
try {
ip_address = asiolink::IOAddress(ip_address_str);
return (isc::asiolink::IOAddress(str));
} catch (const std::exception& ex) {
isc_throw(D2CfgError, "IP address invalid : \""
<< ip_address_str << "\" ("
<< strings->getPosition("ip-address") << ")");
}
if ((ip_address.toText() == "0.0.0.0") || (ip_address.toText() == "::")) {
isc_throw(D2CfgError, "IP address cannot be \"" << ip_address << "\" ("
<< strings->getPosition("ip-address") << ")");
isc_throw(D2CfgError, "invalid address (" << str
<< ") specified for parameter '" << name
<< "' (" << value->getPosition() << ")");
}
}
// Fetch and validate port.
isc::dhcp::Uint32StoragePtr ints = context->getUint32Storage();
uint32_t port = ints->getOptionalParam("port", D2Params::DFT_PORT);
if (port == 0) {
isc_throw(D2CfgError, "port cannot be 0 ("
<< ints->getPosition("port") << ")");
}
// Fetch and validate dns_server_timeout.
uint32_t dns_server_timeout
= ints->getOptionalParam("dns-server-timeout",
D2Params::DFT_DNS_SERVER_TIMEOUT);
if (dns_server_timeout < 1) {
isc_throw(D2CfgError, "DNS server timeout must be larger than 0 ("
<< ints->getPosition("dns-server-timeout") << ")");
dhcp_ddns::NameChangeProtocol
getProtocol(const std::string& name, isc::data::ConstElementPtr value) {
std::string str = value->stringValue();
try {
return (dhcp_ddns::stringToNcrProtocol(str));
} catch (const std::exception& ex) {
isc_throw(D2CfgError,
"invalid NameChangeRequest protocol (" << str
<< ") specified for parameter '" << name
<< "' (" << value->getPosition() << ")");
}
}
// Fetch and validate ncr_protocol.
dhcp_ddns::NameChangeProtocol ncr_protocol;
dhcp_ddns::NameChangeFormat
getFormat(const std::string& name, isc::data::ConstElementPtr value) {
std::string str = value->stringValue();
try {
ncr_protocol = dhcp_ddns::
stringToNcrProtocol(strings->
getOptionalParam("ncr-protocol",
D2Params::
DFT_NCR_PROTOCOL));
return (dhcp_ddns::stringToNcrFormat(str));
} catch (const std::exception& ex) {
isc_throw(D2CfgError, "ncr-protocol : "
<< ex.what() << " ("
<< strings->getPosition("ncr-protocol") << ")");
isc_throw(D2CfgError,
"invalid NameChangeRequest format (" << str
<< ") specified for parameter '" << name
<< "' (" << value->getPosition() << ")");
}
}
if (ncr_protocol != dhcp_ddns::NCR_UDP) {
isc_throw(D2CfgError, "ncr-protocol : "
<< dhcp_ddns::ncrProtocolToString(ncr_protocol)
<< " is not yet supported ("
<< strings->getPosition("ncr-protocol") << ")");
}
} // anon
// Fetch and validate ncr_format.
dhcp_ddns::NameChangeFormat ncr_format;
void
D2CfgMgr::parseElement(const std::string& element_id,
isc::data::ConstElementPtr element) {
try {
ncr_format = dhcp_ddns::
stringToNcrFormat(strings->
getOptionalParam("ncr-format",
D2Params::
DFT_NCR_FORMAT));
// Get D2 specific context.
D2CfgContextPtr context = getD2CfgContext();
if ((element_id == "ip-address") ||
(element_id == "ncr-protocol") ||
(element_id == "ncr-format") ||
(element_id == "port") ||
(element_id == "dns-server-timeout")) {
// global scalar params require nothing extra be done
} else if (element_id == "tsig-keys") {
TSIGKeyInfoListParser parser;
context->setKeys(parser.parse(element));
} else if (element_id == "forward-ddns") {
DdnsDomainListMgrParser parser;
DdnsDomainListMgrPtr mgr = parser.parse(element, element_id,
context->getKeys());
context->setForwardMgr(mgr);
} else if (element_id == "reverse-ddns") {
DdnsDomainListMgrParser parser;
DdnsDomainListMgrPtr mgr = parser.parse(element, element_id,
context->getKeys());
context->setReverseMgr(mgr);
} else {
// Shouldn't occur if the JSON parser is doing its job.
isc_throw(D2CfgError, "Unsupported element: "
<< element_id << element->getPosition());
}
} catch (const D2CfgError& ex) {
// Should already have a specific error and position info
throw ex;
} catch (const std::exception& ex) {
isc_throw(D2CfgError, "ncr-format : "
<< ex.what() << " ("
<< strings->getPosition("ncr-format") << ")");
isc_throw(D2CfgError, "element: " << element_id << " : " << ex.what()
<< element->getPosition());
}
};
void
D2CfgMgr::setCfgDefaults(isc::data::ElementPtr mutable_config) {
D2SimpleParser::setAllDefaults(mutable_config);
}
void
D2CfgMgr::buildParams(isc::data::ConstElementPtr params_config) {
// Base class build creates parses and invokes build on each parser.
// This populate the context scalar stores with all of the parameters.
DCfgMgrBase::buildParams(params_config);
// Fetch the parameters in the config, performing any logcial
// validation required.
asiolink::IOAddress ip_address(0);
uint32_t port = 0;
uint32_t dns_server_timeout = 0;
dhcp_ddns::NameChangeProtocol ncr_protocol = dhcp_ddns::NCR_UDP;
dhcp_ddns::NameChangeFormat ncr_format = dhcp_ddns::FMT_JSON;
// Assumes that params_config has had defaults added
BOOST_FOREACH(isc::dhcp::ConfigPair param, params_config->mapValue()) {
std::string entry(param.first);
isc::data::ConstElementPtr value(param.second);
try {
if (entry == "ip-address") {
ip_address = getIOAddress(entry, value);
if ((ip_address.toText() == "0.0.0.0") ||
(ip_address.toText() == "::")) {
isc_throw(D2CfgError, "IP address cannot be \""
<< ip_address << "\""
<< " (" << value->getPosition() << ")");
}
} else if (entry == "port") {
port = getInt<uint32_t>(entry, value);
} else if (entry == "dns-server-timeout") {
dns_server_timeout = getInt<uint32_t>(entry, value);
} else if (entry == "ncr-protocol") {
ncr_protocol = getProtocol(entry, value);
if (ncr_protocol != dhcp_ddns::NCR_UDP) {
isc_throw(D2CfgError, "ncr-protocol : "
<< dhcp_ddns::ncrProtocolToString(ncr_protocol)
<< " is not yet supported "
<< " (" << value->getPosition() << ")");
}
} else if (entry == "ncr-format") {
ncr_format = getFormat(entry, value);
if (ncr_format != dhcp_ddns::FMT_JSON) {
isc_throw(D2CfgError, "NCR Format:"
<< dhcp_ddns::ncrFormatToString(ncr_format)
<< " is not yet supported"
<< " (" << value->getPosition() << ")");
}
} else {
isc_throw(D2CfgError,
"unsupported parameter '" << entry
<< " (" << value->getPosition() << ")");
}
} catch (const isc::data::TypeError&) {
isc_throw(D2CfgError,
"invalid value type specified for parameter '" << entry
<< " (" << value->getPosition() << ")");
}
if (ncr_format != dhcp_ddns::FMT_JSON) {
isc_throw(D2CfgError, "NCR Format:"
<< dhcp_ddns::ncrFormatToString(ncr_format)
<< " is not yet supported ("
<< strings->getPosition("ncr-format") << ")");
}
// Attempt to create the new client config. This ought to fly as
......@@ -294,44 +363,7 @@ D2CfgMgr::buildParams(isc::data::ConstElementPtr params_config) {
D2ParamsPtr params(new D2Params(ip_address, port, dns_server_timeout,
ncr_protocol, ncr_format));
context->getD2Params() = params;
}
isc::dhcp::ParserPtr
D2CfgMgr::createConfigParser(const std::string& config_id,
const isc::data::Element::Position& pos) {
// Get D2 specific context.
D2CfgContextPtr context = getD2CfgContext();
// Create parser instance based on element_id.
isc::dhcp::ParserPtr parser;
if ((config_id.compare("port") == 0) ||
(config_id.compare("dns-server-timeout") == 0)) {
parser.reset(new isc::dhcp::Uint32Parser(config_id,
context->getUint32Storage()));
} else if ((config_id.compare("ip-address") == 0) ||
(config_id.compare("ncr-protocol") == 0) ||
(config_id.compare("ncr-format") == 0)) {
parser.reset(new isc::dhcp::StringParser(config_id,
context->getStringStorage()));
} else if (config_id == "forward-ddns") {
parser.reset(new DdnsDomainListMgrParser("forward-ddns",
context->getForwardMgr(),
context->getKeys()));
} else if (config_id == "reverse-ddns") {
parser.reset(new DdnsDomainListMgrParser("reverse-ddns",
context->getReverseMgr(),
context->getKeys()));
} else if (config_id == "tsig-keys") {
parser.reset(new TSIGKeyInfoListParser("tsig-key-list",
context->getKeys()));
} else {
isc_throw(NotImplemented,
"parser error: D2CfgMgr parameter not supported : "
" (" << config_id << pos << ")");
}
return (parser);
getD2CfgContext()->getD2Params() = params;
}
}; // end of isc::dhcp namespace
......
// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
//
// 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
......@@ -57,6 +57,12 @@ public:
return (forward_mgr_);
}
/// @brief Sets the forward domain list manager
/// @param forward_mgr pointer to the new forward manager
void setForwardMgr(DdnsDomainListMgrPtr forward_mgr) {
forward_mgr_ = forward_mgr;
}
/// @brief Fetches the reverse DNS domain list manager.
///
/// @return returns a pointer to the reverse manager.
......@@ -64,6 +70,12 @@ public:
return (reverse_mgr_);
}
/// @brief Sets the reverse domain list manager
/// @param reverse_mgr pointer to the new reverse manager
void setReverseMgr(DdnsDomainListMgrPtr reverse_mgr) {
reverse_mgr_ = reverse_mgr;
}
/// @brief Fetches the map of TSIG keys.
///
/// @return returns a pointer to the key map.
......@@ -71,6 +83,13 @@ public:
return (keys_);
}
/// @brief Sets the map of TSIG keys
///
/// @param keys pointer to the new TSIG key map
void setKeys(const TSIGKeyInfoMapPtr& keys) {
keys_ = keys;
}
protected:
/// @brief Copy constructor for use by derivations in clone().
D2CfgContext(const D2CfgContext& rhs);
......@@ -239,6 +258,29 @@ public:
virtual std::string getConfigSummary(const uint32_t selection);
protected:
/// @brief Parses an element using alternate parsers
///
/// Each element to be parsed is passed first into this method to allow
/// it to be processed by SimpleParser derivations if they've been
/// implemented. The method should return true if it has processed the
/// element or false if the element should be passed onto the original
/// DhcpConfigParer mechanisms. This method is invoked in both
/// @c DCfgMgrBase::buildParams() and DCfgMgrBase::buildAndCommit().
///
/// @param element_id name of the element as it is expected in the cfg
/// @param element value of the element as ElementPtr
virtual void parseElement(const std::string& element_id,
isc::data::ConstElementPtr element);
/// @brief Adds default values to the given config
///
/// Adds the D2 default values to the configuration Element map. This
/// method is invoked by @c DCfgMgrBase::paserConfig().
///
/// @param mutable_config - configuration to which defaults should be added
virtual void setCfgDefaults(isc::data::ElementPtr mutable_config);
/// @brief Performs the parsing of the given "params" element.
///
/// Iterates over the set of parameters, creating a parser based on the
......@@ -259,32 +301,6 @@ protected:
/// -# ncr_format is invalid, currently only FMT_JSON is supported
virtual void buildParams(isc::data::ConstElementPtr params_config);
/// @brief Given an element_id returns an instance of the appropriate
/// parser.
///
/// It is responsible for top-level or outermost DHCP-DDNS configuration
/// elements (see dhcp-ddns.spec):
/// -# ip_address
/// -# port
/// -# dns_server_timeout
/// -# ncr_protocol
/// -# ncr_format
/// -# tsig_keys
/// -# forward_ddns
/// -# reverse_ddns
///
/// @param element_id is the string name of the element as it will appear
/// in the configuration set.
/// @param pos position within the configuration text (or file) of element
/// to be parsed. This is passed for error messaging.
///
/// @return returns a ParserPtr to the parser instance.
/// @throw throws DCfgMgrBaseError if an error occurs.
virtual isc::dhcp::ParserPtr
createConfigParser(const std::string& element_id,
const isc::data::Element::Position& pos =
isc::data::Element::Position());
/// @brief Creates an new, blank D2CfgContext context
///
/// This method is used at the beginning of configuration process to
......
This diff is collapsed.
This diff is collapsed.
// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
//
// 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
......@@ -8,6 +8,7 @@
#include <d2/d2_controller.h>
#include <d2/d2_process.h>
#include <d2/parser_context.h>
#include <process/spec_config.h>
#include <stdlib.h>
......@@ -54,6 +55,20 @@ D2Controller::D2Controller()
}
}
isc::data::ConstElementPtr
D2Controller::parseFile(const std::string& file_name) {
isc::data::ConstElementPtr elements;
// Read contents of the file and parse it as JSON
D2ParserContext parser;
elements = parser.parseFile(file_name, D2ParserContext::PARSER_DHCPDDNS);
if (!elements) {
isc_throw(isc::BadValue, "no configuration found in file");
}
return (elements);
}
D2Controller::~D2Controller() {
}
......
// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
//
// 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
......@@ -53,6 +53,17 @@ private:
/// pointer.
virtual process::DProcessBase* createProcess();
///@brief Parse a given file into Elements
///
/// Uses bison parsing to parse a JSON configuration file into an
/// a element map.
///
/// @param file_name pathname of the file to parse
///
/// @return pointer to the map of elements created
/// @throw BadValue if the file is empty
virtual isc::data::ConstElementPtr parseFile(const std::string& file_name);
/// @brief Constructor is declared private to maintain the integrity of
/// the singleton instance.
D2Controller();
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
//
// 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/.
#include <d2/d2_config.h>
#include <d2/d2_simple_parser.h>
#include <cc/data.h>
#include <boost/foreach.hpp>
using namespace isc::data;
namespace isc {
namespace d2 {
/// @brief This sets of arrays define the default values and
/// values inherited (derived) between various scopes.
///
/// Each of those is documented in @file d2_simple_parser.cc. This
/// is different than most other comments in Kea code. The reason
/// for placing those in .cc rather than .h file is that it
/// is expected to be one centralized place to look at for
/// the default values. This is expected to be looked at also by
/// people who are not skilled in C or C++, so they may be
/// confused with the differences between declaration and definition.
/// As such, there's one file to look at that hopefully is readable
/// without any C or C++ skills.
///
/// @{
/// @brief This table defines default global values for D2
///
/// Some of the global parameters defined in the global scope (i.e. directly
/// in DhcpDdns) are optional. If not defined, the following values will be
/// used.
const SimpleDefaults D2SimpleParser::D2_GLOBAL_DEFAULTS = {
{ "ip-address", Element::string, "127.0.0.1" },
{ "port", Element::integer, "53001" },
{ "dns-server-timeout", Element::integer, "100" }, // in seconds
{ "ncr-protocol", Element::string, "UDP" },
{ "ncr-format", Element::string, "JSON" }
};
/// Supplies defaults for ddns-domoains list elements (i.e. DdnsDomains)
const SimpleDefaults D2SimpleParser::TSIG_KEY_DEFAULTS = {
{ "digest-bits", Element::integer, "0" }
};
/// Supplies defaults for optional values in DDNS domain managers
/// (e.g. "forward-ddns" and "reverse-ddns").
/// @note While there are none yet defined, it is highly likely
/// there will be domain manager defaults added in the future.
/// This code to set defaults already uses this list, so supporting
/// values will simply require adding them to this list.
const SimpleDefaults D2SimpleParser::DDNS_DOMAIN_MGR_DEFAULTS = {
};
/// Supplies defaults for ddns-domoains list elements (i.e. DdnsDomains)
const SimpleDefaults D2SimpleParser::DDNS_DOMAIN_DEFAULTS = {
{ "key-name", Element::string, "" }
};
/// Supplies defaults for optional values DdnsDomain entries.
const SimpleDefaults D2SimpleParser::DNS_SERVER_DEFAULTS = {
{ "hostname", Element::string, "" },
{ "port", Element::integer, "53" },
};
/// @}
/// ---------------------------------------------------------------------------
/// --- end of default values -------------------------------------------------
/// ---------------------------------------------------------------------------
size_t
D2SimpleParser::setAllDefaults(isc::data::ElementPtr global) {
size_t cnt = 0;
// Set global defaults first.
cnt = setDefaults(global, D2_GLOBAL_DEFAULTS);
// If the key list is present, set its members' defaults
if (global->find("tsig-keys")) {
ConstElementPtr keys = global->get("tsig-keys");
cnt += setListDefaults(keys, TSIG_KEY_DEFAULTS);
} else {
// Not present, so add an empty list.
ConstElementPtr list(new ListElement());
global->set("tsig-keys", list);
cnt++;
}
// Set the forward domain manager defaults.
cnt += setManagerDefaults(global, "forward-ddns", DDNS_DOMAIN_MGR_DEFAULTS);
// Set the reverse domain manager defaults.
cnt += setManagerDefaults(global, "reverse-ddns", DDNS_DOMAIN_MGR_DEFAULTS);
return (cnt);
}
size_t
D2SimpleParser::setDdnsDomainDefaults(ElementPtr domain,
const SimpleDefaults& domain_defaults) {
size_t cnt = 0;
// Set the domain's scalar defaults
cnt += setDefaults(domain, domain_defaults);
if (domain->find("dns-servers")) {
// Now add the defaults to its server list.
ConstElementPtr servers = domain->get("dns-servers");
cnt += setListDefaults(servers, DNS_SERVER_DEFAULTS);
}
return (cnt);
}