- 4XX. [func] tomek
++525. [func] tomek
+ b10-dhcp4: DHCPv4 server is now able to parse configuration. It
+ is possible to specify IPv4 subnets with dynamic pools within
+ them. Although configuration is accepted, it is not used yet. This
+ will be implemented shortly.
++ (Trac #2270, git de29c07129d41c96ee0d5eebdd30a1ea7fb9ac8a)
++
+ 524. [func] tomek
+ b10-dhcp6 is now able to handle RENEW messages. Leases are
+ renewed and REPLY responses are sent back to clients.
+ (Trac #2325, git 7f6c9d057cc0a7a10f41ce7da9c8565b9ee85246)
+
+ 523. [bug] muks
+ Fixed a problem in inmem NSEC3 lookup (for, instance when using a
+ zone with no non-apex names) which caused exceptions when the zone
+ origin was not added as an explicit NSEC3 record.
+ (Trac #2503, git 6fe86386be0e7598633fe35999112c1a6e3b0370)
+
+ 522. [func]* jelte
+ Configuration of TSIG keys for b10-xfrin has changed; instead of
+ specifying the full TSIG key (<name>:<base64>:<algo>) it now expects
+ just the name, and uses the global TSIG Key Ring like all the other
+ components (configuration list /tsig_keys/keys).
+ Note: this is not automatically updated, so if you use TSIG in
+ xfrin, you need to update your configuration.
+ (Trac #1351, git e65b7b36f60f14b7abe083da411e6934cdfbae7a)
+
+ 521. [func] marcin
+ Implemented definitions for DHCPv6 standard options identified
+ by codes up to 48. These definitions are now used by the DHCPv6
+ server to create instances of options being sent to a client.
+ (Trac #2491, git 0a4faa07777189ed9c25211987a1a9b574015a95)
+
+ 520. [func] jelte
+ The system no longer prints initial log messages to stdout
+ regardless of what logging configuration is present, but it
+ temporarily stores any log messages until the configuration is
+ processed. If there is no specific configuration, or if the
+ configuration cannot be accessed, it will still fall back to stdout.
+ Note that there are still a few instances where output is printed,
+ these shall be addressed separately.
+ Note also that, currently, in case it falls back to stdout (such as
+ when it cannot connect to b10-cfgmgr), all log messages are always
+ printed (including debug messages), regardless of whether -v was
+ used. This shall also be addressed in a future change.
+ (Trac #2445, git 74a0abe5a6d10b28e4a3e360e87b129c232dea68)
+
+ 519. [bug] muks
+ Fixed a problem in inmem NSEC lookup which caused returning an
+ incorrect NSEC record or (in rare cases) assert failures
+ when a non-existent domain was queried, which was a sub-domain of
+ a domain that existed.
+ (Trac #2504, git 835553eb309d100b062051f7ef18422d2e8e3ae4)
+
+ 518. [func] stephen
+ Extend DHCP MySQL backend to handle IPv4 addresses.
+ (Trac #2404, git ce7db48d3ff5d5aad12b1da5e67ae60073cb2607)
+
+ 517. [func] stephen
+ Added IOAddress::toBytes() to get byte representation of address.
+ Also added convenience methods for V4/V6 address determination.
+ (Trac #2396, git c23f87e8ac3ea781b38d688f8f7b58539f85e35a)
+
+ 516. [bug] marcin
+ Fixed 'make distcheck' failure when running perfdhcp unit tests.
+ The unit tests used to read files from the folder specified
+ with the path relative to current folder, thus when the test was
+ run from a different folder the files could not be found.
+ (Trac #2479, git 4e8325e1b309f1d388a3055ec1e1df98c377f383)
+
+ 515. [bug] jinmei
+ The in-memory data source now accepts an RRSIG provided without
+ a covered RRset in loading. A subsequent query for its owner name
+ of the covered type would generally result in NXRRSET; if the
+ covered RRset is of type NSEC3, the corresponding NSEC3 processing
+ would result in SERVFAIL.
+ (Trac #2420, git 6744c100953f6def5500bcb4bfc330b9ffba0f5f)
+
+ 514. [bug] jelte
+ b10-msgq now handles socket errors more gracefully when sending data
+ to clients. It no longer exits with 'broken pipe' errors, and is
+ also better at resending data on temporary error codes from send().
+ (Trac #2398, git 9f6b45ee210a253dca608848a58c824ff5e0d234)
+
+ 513. [func] marcin
+ Implemented the OptionCustom class for DHCPv4 and DHCPv6.
+ This class represents an option which has a defined
+ structure: a set of data fields of specific types and order.
+ It is used to represent those options that can't be
+ represented by any other specialized class.
+ (Trac #2312, git 28d885b457dda970d9aecc5de018ec1120143a10)
+
+ 512. [func] jelte
+ Added a new tool b10-certgen, to check and update the self-signed
+ SSL certificate used by b10-cmdctl. The original certificate
+ provided has been removed, and a fresh one is generated upon first
+ build. See the b10-certgen manpage for information on how to update
+ existing installed certificates.
+ (Trac #1044, git 510773dd9057ccf6caa8241e74a7a0b34ca971ab)
+
+ 511. [bug] stephen
+ Fixed a race condition in the DHCP tests whereby the test program
+ spawned a subprocess and attempted to read (without waiting) from
+ the interconnecting pipe before the subprocess had written
+ anything. The lack of output was being interpreted as a test
+ failure.
+ (Trac #2410, git f53e65cdceeb8e6da4723730e4ed0a17e4646579)
+
+ 510. [func] marcin
+ DHCP option instances can be created using a collection of strings.
+ Each string represents a value of a particular data field within
+ an option. The data field values, given as strings, are validated
+ against the actual types of option fields specified in the options
+ definitions.
+ (Trac #2490, git 56cfd6612fcaeae9acec4a94e1e5f1a88142c44d)
+
+ 509. [func] muks
+ Log messages now include the pid of the process that logged the
+ message.
+ (Trac #1745, git fc8bbf3d438e8154e7c2bdd322145a7f7854dc6a)
+
+ 508. [bug] stephen
+ Split the DHCP library into two directories, each with its own
+ Makefile. This properly solves the problem whereby a "make"
+ operation with multiple threads could fail because of the
+ dependencies between two libraries in the same directory.
+ (Trac #2475, git 834fa9e8f5097c6fd06845620f68547a97da8ff8)
+
+ bind10-devel-20121115 released on November 15, 2012
+
+ 507. [doc] jelte
+ Added a chapter about the use of the bindctl command tool to
+ to the BIND 10 guide.
+ (Trac #2305, git c4b0294b5bf4a9d32fb18ab62ca572f492788d72)
+
+ 506. [security] jinmei
+ Fixed a use-after-free case in handling DNAME record with the
+ in-memory data source. This could lead to a crash of b10-auth
+ if it serves a zone containing a DNAME RR from the in-memory
+ data source. This bug was introduced at bind10-devel-20120927.
+ (Trac #2471, git 2b1793ac78f972ddb1ae2fd092a7f539902223ff)
+
+ 505. [bug] jelte
+ Fixed a bug in b10-xfrin where a wrong call was made during the
+ final check of a TSIG-signed transfer, incorrectly rejecting the
+ transfer.
+ (Trac #2464, git eac81c0cbebee72f6478bdb5cda915f5470d08e1)
+
+ 504. [bug]* naokikambe
+ Fixed an XML format viewed from b10-stats-httpd. Regarding
+ per-zone counters as zones of Xfrout, a part of the item
+ values wasn't an exact XML format. A zone name can be
+ specified in URI as
+ /bind10/statistics/xml/Xfrout/zones/example.org/xfrreqdone.
+ XSD and XSL formats are also changed to constant ones due
+ to these changes.
+ (Trac #2298, git 512d2d46f3cb431bcdbf8d90af27bff8874ba075)
+
+ 503. [func] Stephen
+ Add initial version of a MySQL backend for the DHCP code. This
+ implements the basic IPv6 lease access functions - add lease, delete
+ lease and update lease. The backend is enabled by specifying
+ --with-dhcp-mysql on the "configure" command line: without this
+ switch, the MySQL code is not compiled, so leaving BIND 10 able to
+ be built on systems without MySQL installed.
+ (Trac #2342, git c7defffb89bd0f3fdd7ad2437c78950bcb86ad37)
+
+ 502. [func] vorner
+ TTLs can be specified with units as well as number of seconds now.
+ This allows specifications like "1D3H".
+ (Trac #2384, git 44c321c37e17347f33ced9d0868af0c891ff422b)
+
+ 501. [func] tomek
+ Added DHCPv6 allocation engine, now used in the processing of DHCPv6
+ messages.
+ (Trac #2414, git b3526430f02aa3dc3273612524d23137b8f1fe87)
+
+ 500. [bug] jinmei
+ Corrected the autoconf example in the examples directory so it can
+ use the configured path to Boost to check availability of the BIND 10
+ library. Previously the sample configure script could fail if
+ Boost is installed in an uncommon place. Also, it now provides a
+ helper m4 function and example usage for embedding the library
+ path to executable (using linker options like -Wl,-R) to help
+ minimize post-build hassles.
+ (Trac #2356, git 36514ddc884c02a063e166d44319467ce6fb1d8f)
+
+ 499. [func] team
+ The b10-auth 'loadzone' command now uses the internal thread
+ introduced in 495 to (re)load a zone in the background, so that
+ query processing isn't blocked while loading a zone.
+ (Trac #2213, git 686594e391c645279cc4a95e0e0020d1c01fba7e)
+
+ 498. [func] marcin
+ Implemented DHCPv6 option values configuration using configuration
+ manager. In order to set values for data fields carried by the
+ particular option, user specifies the string of hexadecimal digits
+ that is in turn converted to binary data and stored into option
+ buffer. More user friendly way of option content specification is
+ planned.
+ (Trac #2318, git e75c686cd9c14f4d6c2a242a0a0853314704fee9)
+
+ 497. [bug] jinmei
+ Fixed several issues in isc-sysinfo:
+ - make sure it doesn't report a negative value for free memory
+ size (this happened on FreeBSD, but can possibly occur on other
+ BSD variants)
+ - correctly identifies the SMP support in kernel on FreeBSD
+ - print more human readable uptime as well as the time in seconds
+ (Trac #2297, git 59a449f506948e2371ffa87dcd19059388bd1657)
+
+ 496. [func] tomek
+ DHCPv6 Allocation Engine implemented. It allows address allocation
+ from the configured subnets/pools. It currently features a single
+ allocator: IterativeAllocator, which assigns addresses iteratively.
+ Other allocators (hashed, random) are planned.
+ (Trac #2324, git 8aa188a10298e3a55b725db36502a99d2a8d638a)
+
+ 495. [func] team
+ b10-auth now handles reconfiguration of data sources in
+ background using a separate thread. This means even if the new
+ configuration includes a large amount of data to be loaded into
+ memory (very large zones and/or a very large number of zones),
+ the reconfiguration doesn't block query handling.
+ (Multiple Trac tickets up to #2211)
+
+ 494. [bug] jinmei
+ Fixed a problem that shutting down BIND 10 kept some of the
+ processes alive. It was two-fold: when the main bind10 process
+ started as a root, started b10-sockcreator with the privilege, and
+ then dropped the privilege, the bind10 process cannot kill the
+ sockcreator via signal any more (when it has to), but it kept
+ sending the signal and didn't stop. Also, when running on Python
+ 3.1 (or older), the sockcreator had some additional file
+ descriptor open, which prevented it from exiting even after the
+ bind10 process terminated. Now the bind10 process simply gives up
+ killing a subprocess if it fails due to lack of permission, and it
+ makes sure the socket creator is spawned without any unnecessary
+ FDs open.
+ (Trac #1858, git 405d85c8a0042ba807a3a123611ff383c4081ee1)
+
+ 493. [build] jinmei
+ Fixed build failure with newer versions of clang++. These
+ versions are stricter regarding "unused variable" and "unused
+ (driver) arguments" warnings, and cause fatal build error
+ with -Werror. The affected versions of clang++ include Apple's
+ customized version 4.1 included in Xcode 4.5.1. So this fix
+ will solve build errors for Mac OS X that uses newer versions of
+ Xcode.
+ (Trac #2340, git 55be177fc4f7537143ab6ef5a728bd44bdf9d783,
+ 3e2a372012e633d017a97029d13894e743199741 and commits before it
+ with [2340] in the commit log)
492. [func] tomek
libdhcpsrv: The DHCP Configuration Manager is now able to store
--- /dev/null
- #include <dhcp/cfgmgr.h>
+// Copyright (C) 2012 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/ccsession.h>
++#include <dhcpsrv/cfgmgr.h>
+#include <dhcp4/config_parser.h>
+#include <dhcp4/dhcp4_log.h>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <limits>
+#include <iostream>
+#include <vector>
+#include <map>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+/// @brief auxiliary type used for storing element name and its parser
+typedef pair<string, ConstElementPtr> ConfigPair;
+
+/// @brief a factory method that will create a parser for a given element name
+typedef Dhcp4ConfigParser* ParserFactory(const std::string& config_id);
+
+/// @brief a collection of factories that creates parsers for specified element names
+typedef std::map<std::string, ParserFactory*> FactoryMap;
+
+/// @brief a collection of pools
+///
+/// That type is used as intermediate storage, when pools are parsed, but there is
+/// no subnet object created yet to store them.
+typedef std::vector<Pool4Ptr> PoolStorage;
+
+/// @brief Global uint32 parameters that will be used as defaults.
+Uint32Storage uint32_defaults;
+
+/// @brief global string parameters that will be used as defaults.
+StringStorage string_defaults;
+
+/// @brief a dummy configuration parser
+///
+/// It is a debugging parser. It does not configure anything,
+/// will accept any configuration and will just print it out
+/// on commit. Useful for debugging existing configurations and
+/// adding new ones.
+class DebugParser : public Dhcp4ConfigParser {
+public:
+
+ /// @brief Constructor
+ ///
+ /// See \ref Dhcp4ConfigParser class for details.
+ ///
+ /// @param param_name name of the parsed parameter
+ DebugParser(const std::string& param_name)
+ :param_name_(param_name) {
+ }
+
+ /// @brief builds parameter value
+ ///
+ /// See \ref Dhcp4ConfigParser class for details.
+ ///
+ /// @param new_config pointer to the new configuration
+ virtual void build(ConstElementPtr new_config) {
+ std::cout << "Build for token: [" << param_name_ << "] = ["
+ << value_->str() << "]" << std::endl;
+ value_ = new_config;
+ }
+
+ /// @brief pretends to apply the configuration
+ ///
+ /// This is a method required by base class. It pretends to apply the
+ /// configuration, but in fact it only prints the parameter out.
+ ///
+ /// See \ref Dhcp4ConfigParser class for details.
+ virtual void commit() {
+ // Debug message. The whole DebugParser class is used only for parser
+ // debugging, and is not used in production code. It is very convenient
+ // to keep it around. Please do not turn this cout into logger calls.
+ std::cout << "Commit for token: [" << param_name_ << "] = ["
+ << value_->str() << "]" << std::endl;
+ }
+
+ /// @brief factory that constructs DebugParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static Dhcp4ConfigParser* Factory(const std::string& param_name) {
+ return (new DebugParser(param_name));
+ }
+
+private:
+ /// name of the parsed parameter
+ std::string param_name_;
+
+ /// pointer to the actual value of the parameter
+ ConstElementPtr value_;
+};
+
+/// @brief Configuration parser for uint32 parameters
+///
+/// This class is a generic parser that is able to handle any uint32 integer
+/// type. By default it stores the value in external global container
+/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, \ref Dhcp4ConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// \ref dhcp4-config-inherit page.
+class Uint32Parser : public Dhcp4ConfigParser {
+public:
+
+ /// @brief constructor for Uint32Parser
+ /// @param param_name name of the configuration parameter being parsed
+ Uint32Parser(const std::string& param_name)
+ :storage_(&uint32_defaults), param_name_(param_name) {
+ }
+
+ /// @brief builds parameter value
+ ///
+ /// Parses configuration entry and stores it in a storage. See
+ /// \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
+ /// @throw BadValue if supplied value could not be base to uint32_t
+ virtual void build(ConstElementPtr value) {
+ int64_t check;
+ string x = value->str();
+ try {
+ check = boost::lexical_cast<int64_t>(x);
+ } catch (const boost::bad_lexical_cast &) {
+ isc_throw(BadValue, "Failed to parse value " << value->str()
+ << " as unsigned 32-bit integer.");
+ }
+ if (check > std::numeric_limits<uint32_t>::max()) {
+ isc_throw(BadValue, "Value " << value->str() << "is too large"
+ << " for unsigned 32-bit integer.");
+ }
+ if (check < 0) {
+ isc_throw(BadValue, "Value " << value->str() << "is negative."
+ << " Only 0 or larger are allowed for unsigned 32-bit integer.");
+ }
+
+ // value is small enough to fit
+ value_ = static_cast<uint32_t>(check);
+
+ (*storage_)[param_name_] = value_;
+ }
+
+ /// @brief does nothing
+ ///
+ /// This method is required for all parsers. The value itself
+ /// is not commited anywhere. Higher level parsers are expected to
+ /// use values stored in the storage, e.g. renew-timer for a given
+ /// subnet is stored in subnet-specific storage. It is not commited
+ /// here, but is rather used by \ref Subnet4ConfigParser when constructing
+ /// the subnet.
+ virtual void commit() {
+ }
+
+ /// @brief factory that constructs Uint32Parser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static Dhcp4ConfigParser* Factory(const std::string& param_name) {
+ return (new Uint32Parser(param_name));
+ }
+
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcp4-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
+ void setStorage(Uint32Storage* storage) {
+ storage_ = storage;
+ }
+
+private:
+ /// pointer to the storage, where parsed value will be stored
+ Uint32Storage* storage_;
+
+ /// name of the parameter to be parsed
+ std::string param_name_;
+
+ /// the actual parsed value
+ uint32_t value_;
+};
+
+/// @brief Configuration parser for string parameters
+///
+/// This class is a generic parser that is able to handle any string
+/// parameter. By default it stores the value in external global container
+/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, \ref Dhcp4ConfigParser.
+///
+/// For overview of usability of this generic purpose parser, see
+/// \ref dhcp4-config-inherit page.
+class StringParser : public Dhcp4ConfigParser {
+public:
+
+ /// @brief constructor for StringParser
+ /// @param param_name name of the configuration parameter being parsed
+ StringParser(const std::string& param_name)
+ :storage_(&string_defaults), param_name_(param_name) {
+ }
+
+ /// @brief parses parameter value
+ ///
+ /// Parses configuration entry and stores it in storage. See
+ /// \ref setStorage() for details.
+ ///
+ /// @param value pointer to the content of parsed values
+ virtual void build(ConstElementPtr value) {
+ value_ = value->str();
+ boost::erase_all(value_, "\"");
+
+ (*storage_)[param_name_] = value_;
+ }
+
+ /// @brief does nothing
+ ///
+ /// This method is required for all parser. The value itself
+ /// is not commited anywhere. Higher level parsers are expected to
+ /// use values stored in the storage, e.g. renew-timer for a given
+ /// subnet is stored in subnet-specific storage. It is not commited
+ /// here, but is rather used by its parent parser when constructing
+ /// an object, e.g. the subnet.
+ virtual void commit() {
+ }
+
+ /// @brief factory that constructs StringParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static Dhcp4ConfigParser* Factory(const std::string& param_name) {
+ return (new StringParser(param_name));
+ }
+
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcp4-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
+ void setStorage(StringStorage* storage) {
+ storage_ = storage;
+ }
+
+private:
+ /// pointer to the storage, where parsed value will be stored
+ StringStorage* storage_;
+
+ /// name of the parameter to be parsed
+ std::string param_name_;
+
+ /// the actual parsed value
+ std::string value_;
+};
+
+
+/// @brief parser for interface list definition
+///
+/// This parser handles Dhcp4/interface entry.
+/// 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.
+///
+/// It is useful for parsing Dhcp4/interface parameter.
+class InterfaceListConfigParser : public Dhcp4ConfigParser {
+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
+ /// @throw BadValue if supplied parameter name is not "interface"
+ InterfaceListConfigParser(const std::string& param_name) {
+ if (param_name != "interface") {
+ isc_throw(BadValue, "Internal error. Interface configuration "
+ "parser called for the wrong parameter: " << param_name);
+ }
+ }
+
+ /// @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(ConstElementPtr value) {
+ BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
+ interfaces_.push_back(iface->str());
+ }
+ }
+
+ /// @brief commits interfaces list configuration
+ virtual void commit() {
+ /// @todo: Implement per interface listening. Currently always listening
+ /// on all interfaces.
+ }
+
+ /// @brief factory that constructs InterfaceListConfigParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static Dhcp4ConfigParser* Factory(const std::string& param_name) {
+ return (new InterfaceListConfigParser(param_name));
+ }
+
+private:
+ /// contains list of network interfaces
+ vector<string> interfaces_;
+};
+
+/// @brief parser for pool definition
+///
+/// This parser handles pool definitions, i.e. a list of entries of one
+/// of two syntaxes: min-max and prefix/len. Pool4 objects are created
+/// and stored in chosen PoolStorage container.
+///
+/// As there are no default values for pool, setStorage() must be called
+/// before build(). Otherwise exception will be thrown.
+///
+/// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
+class PoolParser : public Dhcp4ConfigParser {
+public:
+
+ /// @brief constructor.
+ PoolParser(const std::string& /*param_name*/)
+ :pools_(NULL) {
+ // ignore parameter name, it is always Dhcp4/subnet4[X]/pool
+ }
+
+ /// @brief parses the actual list
+ ///
+ /// This method parses the actual list of interfaces.
+ /// No validation is done at this stage, everything is interpreted as
+ /// interface name.
+ /// @param pools_list list of pools defined for a subnet
+ /// @throw InvalidOperation if storage was not specified (setStorage() not called)
+ /// @throw Dhcp4ConfigError when pool parsing fails
+ void build(ConstElementPtr pools_list) {
+ // setStorage() should have been called before build
+ if (!pools_) {
+ isc_throw(InvalidOperation, "Parser logic error. No pool storage set,"
+ " but pool parser asked to parse pools");
+ }
+
+ BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
+
+ // That should be a single pool representation. It should contain
+ // text is form prefix/len or first - last. Note that spaces
+ // are allowed
+ string txt = text_pool->stringValue();
+
+ // first let's remove any whitespaces
+ boost::erase_all(txt, " "); // space
+ boost::erase_all(txt, "\t"); // tabulation
+
+ // Is this prefix/len notation?
+ size_t pos = txt.find("/");
+ if (pos != string::npos) {
+ IOAddress addr("::");
+ uint8_t len = 0;
+ try {
+ addr = IOAddress(txt.substr(0, pos));
+
+ // start with the first character after /
+ string prefix_len = txt.substr(pos + 1);
+
+ // It is lexical cast to int and then downcast to uint8_t.
+ // Direct cast to uint8_t (which is really an unsigned char)
+ // will result in interpreting the first digit as output
+ // value and throwing exception if length is written on two
+ // digits (because there are extra characters left over).
+
+ // No checks for values over 128. Range correctness will
+ // be checked in Pool4 constructor.
+ len = boost::lexical_cast<int>(prefix_len);
+ } catch (...) {
+ isc_throw(Dhcp4ConfigError, "Failed to parse pool "
+ "definition: " << text_pool->stringValue());
+ }
+
+ Pool4Ptr pool(new Pool4(addr, len));
+ pools_->push_back(pool);
+ continue;
+ }
+
+ // Is this min-max notation?
+ pos = txt.find("-");
+ if (pos != string::npos) {
+ // using min-max notation
+ IOAddress min(txt.substr(0,pos));
+ IOAddress max(txt.substr(pos + 1));
+
+ Pool4Ptr pool(new Pool4(min, max));
+
+ pools_->push_back(pool);
+ continue;
+ }
+
+ isc_throw(Dhcp4ConfigError, "Failed to parse pool definition:"
+ << text_pool->stringValue() <<
+ ". Does not contain - (for min-max) nor / (prefix/len)");
+ }
+ }
+
+ /// @brief sets storage for value of this parameter
+ ///
+ /// See \ref dhcp4-config-inherit for details.
+ ///
+ /// @param storage pointer to the storage container
+ void setStorage(PoolStorage* storage) {
+ pools_ = storage;
+ }
+
+ /// @brief does nothing.
+ ///
+ /// This method is required for all parsers. The value itself
+ /// is not commited anywhere. Higher level parsers (for subnet) are expected
+ /// to use values stored in the storage.
+ virtual void commit() {}
+
+ /// @brief factory that constructs PoolParser objects
+ ///
+ /// @param param_name name of the parameter to be parsed
+ static Dhcp4ConfigParser* Factory(const std::string& param_name) {
+ return (new PoolParser(param_name));
+ }
+
+private:
+ /// @brief pointer to the actual Pools storage
+ ///
+ /// That is typically a storage somewhere in Subnet parser
+ /// (an upper level parser).
+ PoolStorage* pools_;
+};
+
+/// @brief this class parses a single subnet
+///
+/// This class parses the whole subnet definition. It creates parsers
+/// for received configuration parameters as needed.
+class Subnet4ConfigParser : public Dhcp4ConfigParser {
+public:
+
+ /// @brief constructor
+ Subnet4ConfigParser(const std::string& ) {
+ // The parameter should always be "subnet", but we don't check here
+ // against it in case someone wants to reuse this parser somewhere.
+ }
+
+ /// @brief parses parameter value
+ ///
+ /// @param subnet pointer to the content of subnet definition
+ void build(ConstElementPtr subnet) {
+
+ BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
+
+ ParserPtr parser(createSubnet4ConfigParser(param.first));
+
+ // if this is an Uint32 parser, tell it to store the values
+ // in values_, rather than in global storage
+ boost::shared_ptr<Uint32Parser> uint_parser =
+ boost::dynamic_pointer_cast<Uint32Parser>(parser);
+ if (uint_parser) {
+ uint_parser->setStorage(&uint32_values_);
+ } else {
+
+ boost::shared_ptr<StringParser> string_parser =
+ boost::dynamic_pointer_cast<StringParser>(parser);
+ if (string_parser) {
+ string_parser->setStorage(&string_values_);
+ } else {
+
+ boost::shared_ptr<PoolParser> pool_parser =
+ boost::dynamic_pointer_cast<PoolParser>(parser);
+ if (pool_parser) {
+ pool_parser->setStorage(&pools_);
+ }
+ }
+ }
+
+ parser->build(param.second);
+ parsers_.push_back(parser);
+ }
+
+ // Ok, we now have subnet parsed
+ }
+
+ /// @brief commits received configuration.
+ ///
+ /// This method does most of the configuration. Many other parsers are just
+ /// storing the values that are actually consumed here. Pool definitions
+ /// created in other parsers are used here and added to newly created Subnet4
+ /// objects. Subnet4 are then added to DHCP CfgMgr.
+ /// @throw Dhcp4ConfigError if there are any issues encountered during commit
+ void commit() {
+
+ StringStorage::const_iterator it = string_values_.find("subnet");
+ if (it == string_values_.end()) {
+ isc_throw(Dhcp4ConfigError,
+ "Mandatory subnet definition in subnet missing");
+ }
+ string subnet_txt = it->second;
+ boost::erase_all(subnet_txt, " ");
+ boost::erase_all(subnet_txt, "\t");
+
+ size_t pos = subnet_txt.find("/");
+ if (pos == string::npos) {
+ isc_throw(Dhcp4ConfigError,
+ "Invalid subnet syntax (prefix/len expected):" << it->second);
+ }
+ IOAddress addr(subnet_txt.substr(0, pos));
+ uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
+
+ Triplet<uint32_t> t1 = getParam("renew-timer");
+ Triplet<uint32_t> t2 = getParam("rebind-timer");
+ Triplet<uint32_t> valid = getParam("valid-lifetime");
+
+ /// @todo: Convert this to logger once the parser is working reliably
+ stringstream tmp;
+ tmp << addr.toText() << "/" << (int)len
+ << " with params t1=" << t1 << ", t2=" << t2 << ", valid=" << valid;
+
+ LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(tmp.str());
+
+ Subnet4Ptr subnet(new Subnet4(addr, len, t1, t2, valid));
+
+ for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
+ subnet->addPool4(*it);
+ }
+
+ CfgMgr::instance().addSubnet4(subnet);
+ }
+
+private:
+
+ /// @brief creates parsers for entries in subnet definition
+ ///
+ /// @todo Add subnet-specific things here (e.g. subnet-specific options)
+ ///
+ /// @param config_id name od the entry
+ /// @return parser object for specified entry name
+ /// @throw NotImplemented if trying to create a parser for unknown config element
+ Dhcp4ConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
+ FactoryMap factories;
+
+ factories["valid-lifetime"] = Uint32Parser::Factory;
+ factories["renew-timer"] = Uint32Parser::Factory;
+ factories["rebind-timer"] = Uint32Parser::Factory;
+ factories["subnet"] = StringParser::Factory;
+ factories["pool"] = PoolParser::Factory;
+
+ FactoryMap::iterator f = factories.find(config_id);
+ if (f == factories.end()) {
+ // Used for debugging only.
+ // return new DebugParser(config_id);
+
+ isc_throw(NotImplemented,
+ "Parser error: Subnet4 parameter not supported: "
+ << config_id);
+ }
+ return (f->second(config_id));
+ }
+
+ /// @brief returns value for a given parameter (after using inheritance)
+ ///
+ /// This method implements inheritance. For a given parameter name, it first
+ /// checks if there is a global value for it and overwrites it with specific
+ /// value if such value was defined in subnet.
+ ///
+ /// @param name name of the parameter
+ /// @return triplet with the parameter name
+ /// @throw Dhcp4ConfigError when requested parameter is not present
+ Triplet<uint32_t> getParam(const std::string& name) {
+ uint32_t value = 0;
+ bool found = false;
+ Uint32Storage::iterator global = uint32_defaults.find(name);
+ if (global != uint32_defaults.end()) {
+ value = global->second;
+ found = true;
+ }
+
+ Uint32Storage::iterator local = uint32_values_.find(name);
+ if (local != uint32_values_.end()) {
+ value = local->second;
+ found = true;
+ }
+
+ if (found) {
+ return (Triplet<uint32_t>(value));
+ } else {
+ isc_throw(Dhcp4ConfigError, "Mandatory parameter " << name
+ << " missing (no global default and no subnet-"
+ << "specific value)");
+ }
+ }
+
+ /// storage for subnet-specific uint32 values
+ Uint32Storage uint32_values_;
+
+ /// storage for subnet-specific integer values
+ StringStorage string_values_;
+
+ /// storage for pools belonging to this subnet
+ PoolStorage pools_;
+
+ /// parsers are stored here
+ ParserCollection parsers_;
+};
+
+/// @brief this class parses list of 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 Dhcp4ConfigParser {
+public:
+
+ /// @brief constructor
+ ///
+ Subnets4ListConfigParser(const std::string&) {
+ /// parameter name is ignored
+ }
+
+ /// @brief parses contents of the list
+ ///
+ /// Iterates over all entries on the list and creates Subnet4ConfigParser
+ /// for each entry.
+ ///
+ /// @param subnets_list pointer to a list of IPv4 subnets
+ void build(ConstElementPtr subnets_list) {
+
+ // No need to define FactoryMap here. There's only one type
+ // used: Subnet4ConfigParser
+
+ BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
+
+ ParserPtr parser(new Subnet4ConfigParser("subnet"));
+ parser->build(subnet);
+ subnets_.push_back(parser);
+ }
+
+ }
+
+ /// @brief commits subnets definitions.
+ ///
+ /// Iterates over all Subnet4 parsers. Each parser contains definitions
+ /// of a single subnet and its parameters and commits each subnet separately.
+ void commit() {
+ // @todo: Implement more subtle reconfiguration than toss
+ // the old one and replace with the new one.
+
+ // remove old subnets
+ CfgMgr::instance().deleteSubnets4();
+
+ BOOST_FOREACH(ParserPtr subnet, subnets_) {
+ subnet->commit();
+ }
+
+ }
+
+ /// @brief Returns Subnet4ListConfigParser object
+ /// @param param_name name of the parameter
+ /// @return Subnets4ListConfigParser object
+ static Dhcp4ConfigParser* Factory(const std::string& param_name) {
+ return (new Subnets4ListConfigParser(param_name));
+ }
+
+ /// @brief collection of subnet parsers.
+ ParserCollection subnets_;
+};
+
+/// @brief creates global parsers
+///
+/// This method creates global parsers that parse global parameters, i.e.
+/// those that take format of Dhcp4/param1, Dhcp4/param2 and so forth.
+///
+/// @param config_id pointer to received global configuration entry
+/// @return parser for specified global DHCPv4 parameter
+/// @throw NotImplemented if trying to create a parser for unknown config element
+Dhcp4ConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
+ FactoryMap factories;
+
+ factories["valid-lifetime"] = Uint32Parser::Factory;
+ factories["renew-timer"] = Uint32Parser::Factory;
+ factories["rebind-timer"] = Uint32Parser::Factory;
+ factories["interface"] = InterfaceListConfigParser::Factory;
+ factories["subnet4"] = Subnets4ListConfigParser::Factory;
+ factories["version"] = StringParser::Factory;
+
+ FactoryMap::iterator f = factories.find(config_id);
+ if (f == factories.end()) {
+ // Used for debugging only.
+ // return new DebugParser(config_id);
+
+ isc_throw(NotImplemented,
+ "Parser error: Global configuration parameter not supported: "
+ << config_id);
+ }
+ return (f->second(config_id));
+}
+
+isc::data::ConstElementPtr
+configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
+ if (!config_set) {
+ ConstElementPtr answer = isc::config::createAnswer(1,
+ string("Can't parse NULL config"));
+ return (answer);
+ }
+
+ /// @todo: append most essential info here (like "2 new subnets configured")
+ string config_details;
+
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_START).arg(config_set->str());
+
+ ParserCollection parsers;
+ try {
+ BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
+
+ ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first));
+ parser->build(config_pair.second);
+ parsers.push_back(parser);
+ }
+ } catch (const isc::Exception& ex) {
+ ConstElementPtr answer = isc::config::createAnswer(1,
+ string("Configuration parsing failed:") + ex.what());
+ return (answer);
+ } catch (...) {
+ // for things like bad_cast in boost::lexical_cast
+ ConstElementPtr answer = isc::config::createAnswer(1,
+ string("Configuration parsing failed"));
+ }
+
+ try {
+ BOOST_FOREACH(ParserPtr parser, parsers) {
+ parser->commit();
+ }
+ }
+ catch (const isc::Exception& ex) {
+ ConstElementPtr answer = isc::config::createAnswer(2,
+ string("Configuration commit failed:") + ex.what());
+ return (answer);
+ } catch (...) {
+ // for things like bad_cast in boost::lexical_cast
+ ConstElementPtr answer = isc::config::createAnswer(2,
+ string("Configuration commit failed"));
+ }
+
+ LOG_INFO(dhcp4_logger, DHCP4_CONFIG_COMPLETE).arg(config_details);
+
+ ConstElementPtr answer = isc::config::createAnswer(0, "Configuration commited.");
+ return (answer);
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
--- /dev/null
- #include <dhcp/subnet.h>
- #include <dhcp/cfgmgr.h>
+// Copyright (C) 2012 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 <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <dhcp4/dhcp4_srv.h>
+#include <dhcp4/config_parser.h>
+#include <config/ccsession.h>
++#include <dhcpsrv/subnet.h>
++#include <dhcpsrv/cfgmgr.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <limits.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::config;
+
+namespace isc {
+namespace dhcp {
+extern Uint32Storage uint32_defaults;
+}
+}
+
+namespace {
+
+class Dhcp4ParserTest : public ::testing::Test {
+public:
+ Dhcp4ParserTest()
+ :rcode_(-1) {
+ // Open port 0 means to not do anything at all. We don't want to
+ // deal with sockets here, just check if configuration handling
+ // is sane.
+ srv_ = new Dhcpv4Srv(0);
+ }
+
+ // Checks if global parameter of name have expected_value
+ void checkGlobalUint32(string name, uint32_t expected_value) {
+ Uint32Storage::const_iterator it = uint32_defaults.find(name);
+ if (it == uint32_defaults.end()) {
+ ADD_FAILURE() << "Expected uint32 with name " << name
+ << " not found";
+ return;
+ }
+ EXPECT_EQ(expected_value, it->second);
+ }
+
+ // Checks if config_result (result of DHCP server configuration) has
+ // expected code (0 for success, other for failures).
+ // Also stores result in rcode_ and comment_.
+ void checkResult(ConstElementPtr status, int expected_code) {
+ ASSERT_TRUE(status);
+ comment_ = parseAnswer(rcode_, status);
+ EXPECT_EQ(expected_code, rcode_);
+ }
+
+ ~Dhcp4ParserTest() {
+ delete srv_;
+ };
+
+ Dhcpv4Srv* srv_;
+
+ int rcode_;
+ ConstElementPtr comment_;
+};
+
+// Goal of this test is a verification if a very simple config update
+// with just a bumped version number. That's the simplest possible
+// config update.
+TEST_F(Dhcp4ParserTest, version) {
+
+ ConstElementPtr x;
+
+ EXPECT_NO_THROW(x = configureDhcp4Server(*srv_,
+ Element::fromJSON("{\"version\": 0}")));
+
+ // returned value must be 0 (configuration accepted)
+ checkResult(x, 0);
+}
+
+/// The goal of this test is to verify that the code accepts only
+/// valid commands and malformed or unsupported parameters are rejected.
+TEST_F(Dhcp4ParserTest, bogusCommand) {
+
+ ConstElementPtr x;
+
+ EXPECT_NO_THROW(x = configureDhcp4Server(*srv_,
+ Element::fromJSON("{\"bogus\": 5}")));
+
+ // returned value must be 1 (configuration parse error)
+ checkResult(x, 1);
+}
+
+/// The goal of this test is to verify if wrongly defined subnet will
+/// be rejected. Properly defined subnet must include at least one
+/// pool definition.
+TEST_F(Dhcp4ParserTest, emptySubnet) {
+
+ ConstElementPtr status;
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+ Element::fromJSON("{ \"interface\": [ \"all\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ ], "
+ "\"valid-lifetime\": 4000 }")));
+
+ // returned value should be 0 (success)
+ checkResult(status, 0);
+
+ checkGlobalUint32("rebind-timer", 2000);
+ checkGlobalUint32("renew-timer", 1000);
+ checkGlobalUint32("valid-lifetime", 4000);
+}
+
+/// The goal of this test is to verify if defined subnet uses global
+/// parameter timer definitions.
+TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+
+ // check if returned status is OK
+ checkResult(status, 0);
+
+ // Now check if the configuration was indeed handled and we have
+ // expected pool configured.
+ Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(1000, subnet->getT1());
+ EXPECT_EQ(2000, subnet->getT2());
+ EXPECT_EQ(4000, subnet->getValid());
+}
+
+// This test checks if it is possible to override global values
+// on a per subnet basis.
+TEST_F(Dhcp4ParserTest, subnetLocal) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+ " \"renew-timer\": 1, "
+ " \"rebind-timer\": 2, "
+ " \"valid-lifetime\": 4,"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+
+ // returned value should be 0 (configuration success)
+ checkResult(status, 0);
+
+ Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(1, subnet->getT1());
+ EXPECT_EQ(2, subnet->getT2());
+ EXPECT_EQ(4, subnet->getValid());
+}
+
+// Test verifies that a subnet with pool values that do not belong to that
+// pool are rejected.
+TEST_F(Dhcp4ParserTest, poolOutOfSubnet) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.4.0/28\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+
+ // returned value must be 2 (values error)
+ // as the pool does not belong to that subnet
+ checkResult(status, 2);
+}
+
+// Goal of this test is to verify if pools can be defined
+// using prefix/length notation. There is no separate test for min-max
+// notation as it was tested in several previous tests.
+TEST_F(Dhcp4ParserTest, poolPrefixLen) {
+
+ ConstElementPtr status;
+
+ string config = "{ \"interface\": [ \"all\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.128/28\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ "\"valid-lifetime\": 4000 }";
+ cout << config << endl;
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+
+ // returned value must be 0 (configuration accepted)
+ checkResult(status, 0);
+
+ Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(1000, subnet->getT1());
+ EXPECT_EQ(2000, subnet->getT2());
+ EXPECT_EQ(4000, subnet->getValid());
+}
+
+/// This test checks if Uint32Parser can really parse the whole range
+/// and properly err of out of range values. As we can't call Uint32Parser
+/// directly, we are exploiting the fact that it is used to parse global
+/// parameter renew-timer and the results are stored in uint32_defaults.
+TEST_F(Dhcp4ParserTest, Uint32Parser) {
+
+ ConstElementPtr status;
+
+ // CASE 1: 0 - minimum value, should work
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+ Element::fromJSON("{\"version\": 0,"
+ "\"renew-timer\": 0}")));
+
+ // returned value must be ok (0 is a proper value)
+ checkResult(status, 0);
+ checkGlobalUint32("renew-timer", 0);
+
+ // CASE 2: 4294967295U (UINT_MAX) should work as well
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+ Element::fromJSON("{\"version\": 0,"
+ "\"renew-timer\": 4294967295}")));
+
+ // returned value must be ok (0 is a proper value)
+ checkResult(status, 0);
+ checkGlobalUint32("renew-timer", 4294967295U);
+
+ // CASE 3: 4294967296U (UINT_MAX + 1) should not work
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+ Element::fromJSON("{\"version\": 0,"
+ "\"renew-timer\": 4294967296}")));
+
+ // returned value must be rejected (1 configuration error)
+ checkResult(status, 1);
+
+ // CASE 4: -1 (UINT_MIN -1 ) should not work
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+ Element::fromJSON("{\"version\": 0,"
+ "\"renew-timer\": -1}")));
+
+ // returned value must be rejected (1 configuration error)
+ checkResult(status, 1);
+}
+
+};