libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/host_reservations_list_parser.h
+libkea_dhcpsrv_la_SOURCES += parsers/ifaces_config_parser.cc
+libkea_dhcpsrv_la_SOURCES += parsers/ifaces_config_parser.h
nodist_libkea_dhcpsrv_la_SOURCES = dhcpsrv_messages.h dhcpsrv_messages.cc
boost::erase_all(value_, "\"");
}
-// ******************** InterfaceListConfigParser *************************
-
-InterfaceListConfigParser::
-InterfaceListConfigParser(const std::string& param_name,
- ParserContextPtr global_context)
- : param_name_(param_name), global_context_(global_context) {
- if (param_name_ != "interfaces") {
- isc_throw(BadValue, "Internal error. Interface configuration "
- "parser called for the wrong parameter: " << param_name);
- }
-}
-
-void
-InterfaceListConfigParser::build(ConstElementPtr value) {
- CfgIface cfg_iface;
-
- BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
- std::string iface_name = iface->stringValue();
- try {
- cfg_iface.use(global_context_->universe_ == Option::V4 ?
- AF_INET : AF_INET6, iface_name);
-
- } catch (const std::exception& ex) {
- isc_throw(DhcpConfigError, "Failed to select interface: "
- << ex.what() << " (" << value->getPosition() << ")");
- }
- }
- CfgMgr::instance().getStagingCfg()->setCfgIface(cfg_iface);
-}
-
-void
-InterfaceListConfigParser::commit() {
- // Nothing to do.
-}
-
// ******************** MACSourcesListConfigParser *************************
MACSourcesListConfigParser::
};
-/// @brief parser for interface list definition
-///
-/// This parser handles Dhcp4/interfaces and Dhcp6/interfaces entries.
-/// It contains a list of network interfaces that the server listens on.
-/// In particular, it can contain an entry called "all" or "any" that
-/// designates all interfaces.
-class InterfaceListConfigParser : public DhcpConfigParser {
-public:
-
- /// @brief constructor
- ///
- /// As this is a dedicated parser, it must be used to parse
- /// "interface" parameter only. All other types will throw exception.
- ///
- /// @param param_name name of the configuration parameter being parsed
- /// @param global_context Global parser context.
- /// @throw BadValue if supplied parameter name is not "interface"
- InterfaceListConfigParser(const std::string& param_name,
- ParserContextPtr global_context);
-
- /// @brief parses parameters value
- ///
- /// Parses configuration entry (list of parameters) and adds each element
- /// to the interfaces list.
- ///
- /// @param value pointer to the content of parsed values
- virtual void build(isc::data::ConstElementPtr value);
-
- /// @brief Does nothing.
- virtual void commit();
-
-private:
-
- // Parsed parameter name
- std::string param_name_;
-
- /// Global parser context.
- ParserContextPtr global_context_;
-};
-
-
/// @brief parser for MAC/hardware aquisition sources
///
/// This parser handles Dhcp6/mac-sources entry.
--- /dev/null
+// 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 <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/parsers/ifaces_config_parser.h>
+#include <boost/foreach.hpp>
+#include <string>
+#include <sys/types.h>
+
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+InterfaceListConfigParser::InterfaceListConfigParser(const int protocol)
+ : protocol_(protocol) {
+}
+
+void
+InterfaceListConfigParser::build(ConstElementPtr value) {
+ CfgIface cfg_iface;
+
+ BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
+ std::string iface_name = iface->stringValue();
+ try {
+ cfg_iface.use(protocol_, iface_name);
+
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, "Failed to select interface: "
+ << ex.what() << " (" << value->getPosition() << ")");
+ }
+ }
+ CfgMgr::instance().getStagingCfg()->setCfgIface(cfg_iface);
+}
+
+void
+InterfaceListConfigParser::commit() {
+ // Nothing to do.
+}
+
+IfacesConfigParser::IfacesConfigParser(const int protocol)
+ : protocol_(protocol) {
+}
+
+void
+IfacesConfigParser::build(isc::data::ConstElementPtr ifaces_config) {
+ BOOST_FOREACH(ConfigPair element, ifaces_config->mapValue()) {
+ try {
+ if (element.first == "interfaces") {
+ InterfaceListConfigParser parser(protocol_);
+ parser.build(element.second);
+
+ }
+
+ } catch (const std::exception& ex) {
+ // Append line number where the error occurred.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << element.second->getPosition() << ")");
+ }
+ }
+}
+
+bool
+IfacesConfigParser::isGenericParameter(const std::string& parameter) const {
+ // Currently, the "interfaces" is the only common parameter for
+ // DHCPv4 and DHCPv6.
+ return (parameter == "interfaces");
+}
+
+IfacesConfigParser4::IfacesConfigParser4()
+ : IfacesConfigParser(AF_INET) {
+}
+
+void
+IfacesConfigParser4::build(isc::data::ConstElementPtr ifaces_config) {
+ IfacesConfigParser::build(ifaces_config);
+ BOOST_FOREACH(ConfigPair element, ifaces_config->mapValue()) {
+ try {
+ if (element.first == "socket-type") {
+ /// @todo set socket-type
+
+ } else if (!isGenericParameter(element.first)) {
+ isc_throw(DhcpConfigError, "usupported parameter '"
+ << element.first << "'");
+ }
+
+ } catch (const std::exception& ex) {
+ // Append line number where the error occurred.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << element.second->getPosition() << ")");
+ }
+ }
+}
+
+IfacesConfigParser6::IfacesConfigParser6()
+ : IfacesConfigParser(AF_INET6) {
+}
+
+void
+IfacesConfigParser6::build(isc::data::ConstElementPtr ifaces_config) {
+ IfacesConfigParser::build(ifaces_config);
+
+ BOOST_FOREACH(ConfigPair element, ifaces_config->mapValue()) {
+ try {
+ if (!isGenericParameter(element.first)) {
+ isc_throw(DhcpConfigError, "usupported parameter '"
+ << element.first << "'");
+ }
+
+ } catch (const std::exception& ex) {
+ // Append line number where the error occurred.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << element.second->getPosition() << ")");
+ }
+ }
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
--- /dev/null
+// 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 IFACES_CONFIG_PARSER_H
+#define IFACES_CONFIG_PARSER_H
+
+#include <cc/data.h>
+#include <dhcpsrv/parsers/dhcp_config_parser.h>
+#include <dhcpsrv/parsers/dhcp_parsers.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Parser for interface list definition.
+///
+/// This parser handles Dhcp4/interface-config/interfaces and
+/// Dhcp6/interface-config/interfaces entries.
+/// It contains a list of network interfaces that the server listens on.
+/// In particular, it can contain an "*" that designates all interfaces.
+class InterfaceListConfigParser : public DhcpConfigParser {
+public:
+
+ /// @brief Constructor
+ ///
+ /// @param protocol AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
+ ///
+ /// @throw BadValue if supplied parameter name is not "interface"
+ InterfaceListConfigParser(const int protocol);
+
+ /// @brief Parses a list of interface names.
+ ///
+ /// This method parses a list of interface/address tuples in a text
+ /// format. The tuples specify the IP addresses and corresponding
+ /// interface names on which the server should listen to the DHCP
+ /// messages. The address is optional in each tuple and, if not
+ /// specified, the interface name (without slash character) should
+ /// be present.
+ ///
+ /// @param value pointer to the content of parsed values
+ ///
+ /// @throw DhcpConfigError if the interface names and/or addresses
+ /// are invalid.
+ virtual void build(isc::data::ConstElementPtr value);
+
+ /// @brief Does nothing.
+ virtual void commit();
+
+private:
+
+ /// @brief AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
+ int protocol_;
+
+};
+
+
+/// @brief Parser for the configuration of interfaces.
+///
+/// This parser parses the "interface-config" parameter which holds the
+/// full configuration of the DHCP server with respect to the use of
+/// interfaces, sockets and alike.
+///
+/// This parser uses the @c InterfaceListConfigParser to parse the
+/// list of interfaces on which the server should listen. It handles
+/// remaining parameters internally.
+///
+/// This parser is used as a base for the DHCPv4 and DHCPv6 specific
+/// parsers and should not be used directly.
+class IfacesConfigParser : public DhcpConfigParser {
+public:
+
+ /// @brief Constructor
+ ///
+ /// @param protocol AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
+ IfacesConfigParser(const int protocol);
+
+ /// @brief Parses generic parameters in "interface-config".
+ ///
+ /// The generic parameters in the "interface-config" map are
+ /// the ones that are common for DHCPv4 and DHCPv6.
+ ///
+ /// @param ifaces_config A data element holding configuration of
+ /// interfaces.
+ virtual void build(isc::data::ConstElementPtr ifaces_config);
+
+ /// @brief Commit, unused.
+ virtual void commit() { }
+
+ /// @brief Checks if the specified parameter is a common parameter
+ /// for DHCPv4 and DHCPv6 interface configuration.
+ ///
+ /// This method is invoked by the derived classes to check if the
+ /// particular parameter is supported.
+ ///
+ /// @param parameter A name of the parameter.
+ ///
+ /// @return true if the specified parameter is a common parameter
+ /// for DHCPv4 and DHCPv6 server.
+ bool isGenericParameter(const std::string& parameter) const;
+
+private:
+
+ /// @brief AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
+ int protocol_;
+
+};
+
+
+/// @brief Parser for the "interface-config" parameter of the DHCPv4 server.
+class IfacesConfigParser4 : public IfacesConfigParser {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// Sets the protocol to AF_INET.
+ IfacesConfigParser4();
+
+ /// @brief Parses DHCPv4 specific parameters.
+ ///
+ /// Internally it invokes the @c InterfaceConfigParser::build to parse
+ /// generic parameters. In addition, it parses the following parameters:
+ /// - socket-type
+ ///
+ /// @param ifaces_config A data element holding configuration of
+ /// interfaces.
+ ///
+ /// @throw DhcpConfigError if unsupported parameters is specified.
+ virtual void build(isc::data::ConstElementPtr ifaces_config);
+
+};
+
+/// @brief Parser for the "interface-config" parameter of the DHCPv4 server.
+class IfacesConfigParser6 : public IfacesConfigParser {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// Sets the protocol to AF_INET6.
+ IfacesConfigParser6();
+
+ /// @brief Parses DHCPv6 specific parameters.
+ ///
+ /// Internally it invokes the @c InterfaceConfigParser::build to parse
+ /// generic parameters. Currently it doesn't parse any other parameters.
+ ///
+ /// @param ifaces_config A data element holding configuration of
+ /// interfaces.
+ ///
+ /// @throw DhcpConfigError if unsupported parameters is specified.
+ virtual void build(isc::data::ConstElementPtr ifaces_config);
+
+};
+
+}
+} // end of namespace isc
+
+#endif // IFACES_CONFIG_PARSER_H
libdhcpsrv_unittests_SOURCES += host_unittest.cc
libdhcpsrv_unittests_SOURCES += host_reservation_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += host_reservations_list_parser_unittest.cc
+libdhcpsrv_unittests_SOURCES += ifaces_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_file_io.cc lease_file_io.h
libdhcpsrv_unittests_SOURCES += lease_file_loader_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_unittest.cc
EXPECT_EQ(test_value, actual_value);
}
-/// @brief Check InterfaceListConfigParser basic functionality
-///
-/// Verifies that the parser:
-/// 1. Does not allow empty for storage.
-/// 2. Does not allow name other than "interfaces"
-/// 3. Parses list of interfaces and adds them to CfgMgr
-/// 4. Parses wildcard interface name and sets a CfgMgr flag which indicates
-/// that server will listen on all interfaces.
-TEST_F(DhcpParserTest, interfaceListParserTest) {
- IfaceMgrTestConfig test_config(true);
-
- const std::string name = "interfaces";
-
- ParserContextPtr parser_context(new ParserContext(Option::V4));
-
- // Verify that parser constructor fails if parameter name isn't "interface"
- EXPECT_THROW(InterfaceListConfigParser("bogus_name", parser_context),
- isc::BadValue);
-
- boost::scoped_ptr<InterfaceListConfigParser>
- parser(new InterfaceListConfigParser(name, parser_context));
- ElementPtr list_element = Element::createList();
- list_element->add(Element::create("eth0"));
-
- // This should parse the configuration and add eth0 and eth1 to the list
- // of interfaces that server should listen on.
- parser->build(list_element);
- parser->commit();
-
- // Use CfgMgr instance to check if eth0 and eth1 was added, and that
- // eth2 was not added.
- SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
- ASSERT_TRUE(cfg);
- ASSERT_NO_THROW(cfg->getCfgIface().openSockets(AF_INET, 10000));
-
- EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
- EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET));
-
- // Add keyword all to the configuration. This should activate all
- // interfaces, including eth2, even though it has not been explicitly
- // added.
- list_element->add(Element::create("*"));
-
- // Reset parser and configuration.
- parser.reset(new InterfaceListConfigParser(name, parser_context));
- cfg->getCfgIface().closeSockets();
- CfgMgr::instance().clear();
-
- parser->build(list_element);
- parser->commit();
-
- cfg = CfgMgr::instance().getStagingCfg();
- ASSERT_NO_THROW(cfg->getCfgIface().openSockets(AF_INET, 10000));
-
- EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
- EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET));
-}
-
-
/// @brief Check MACSourcesListConfigParser basic functionality
///
/// Verifies that the parser:
--- /dev/null
+// 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/tests/iface_mgr_test_config.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/parsers/ifaces_config_parser.h>
+#include <gtest/gtest.h>
+
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+
+namespace {
+
+/// @brief Test fixture class for @c IfacesConfigParser
+class IfacesConfigParserTest : public ::testing::Test {
+protected:
+
+ /// @brief Setup for each test.
+ ///
+ /// Clears the configuration in the @c CfgMgr.
+ virtual void SetUp();
+
+ /// @brief Cleans up after each test.
+ ///
+ /// Clears the configuration in the @c CfgMgr.
+ virtual void TearDown();
+
+};
+
+void
+IfacesConfigParserTest::SetUp() {
+ CfgMgr::instance().clear();
+}
+
+void
+IfacesConfigParserTest::TearDown() {
+ CfgMgr::instance().clear();
+}
+
+// This test checks that the parser correctly parses the list of interfaces
+// on which the server should listen.
+TEST_F(IfacesConfigParserTest, interfaces) {
+ // Creates fake interfaces with fake addresses.
+ IfaceMgrTestConfig test_config(true);
+
+ // Configuration with one interface.
+ std::string config = "{"
+ "\"interfaces\": [ \"eth0\" ],"
+ "\"socket-type\": \"raw\" }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ // Parse the configuration.
+ IfacesConfigParser4 parser;
+ ASSERT_NO_THROW(parser.build(config_element));
+
+ // Open sockets according to the parsed configuration.
+ SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
+ ASSERT_TRUE(cfg);
+ ASSERT_NO_THROW(cfg->getCfgIface().openSockets(AF_INET, 10000));
+
+ // Only eth0 should have an open socket.
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
+ EXPECT_FALSE(test_config.socketOpen("eth1", AF_INET));
+
+ // Reset configuration.
+ cfg->getCfgIface().closeSockets();
+ CfgMgr::instance().clear();
+
+ // Try similar configuration but this time add a wildcard interface
+ // to see if sockets will open on all interfaces.
+ config = "{"
+ "\"interfaces\": [ \"eth0\", \"*\" ],"
+ "\"socket-type\": \"raw\" }";
+
+ config_element = Element::fromJSON(config);
+
+ ASSERT_NO_THROW(parser.build(config_element));
+
+ cfg = CfgMgr::instance().getStagingCfg();
+ ASSERT_NO_THROW(cfg->getCfgIface().openSockets(AF_INET, 10000));
+
+ EXPECT_TRUE(test_config.socketOpen("eth0", AF_INET));
+ EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET));
+}
+
+
+} // end of anonymous namespace