]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[540-recommend-moving-hostname-char-set-and-hostname-char-replacement-out-of-dhcp...
authorFrancis Dupont <fdupont@isc.org>
Mon, 10 Jun 2019 19:07:12 +0000 (21:07 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 13 Jun 2019 13:21:07 +0000 (15:21 +0200)
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp6/tests/config_parser_unittest.cc
src/lib/dhcpsrv/d2_client_cfg.cc
src/lib/dhcpsrv/d2_client_cfg.h
src/lib/dhcpsrv/parsers/dhcp_parsers.cc
src/lib/dhcpsrv/parsers/simple_parser4.cc

index a96e38d02067d00f1fa26e8b24c39e0025688876..93925008d18f229bf3a1f7192dad47296eee0351 100644 (file)
@@ -1447,6 +1447,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
 
 \"hostname-char-set\" {
     switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP4:
     case isc::dhcp::Parser4Context::DHCP_DDNS:
         return isc::dhcp::Dhcp4Parser::make_HOSTNAME_CHAR_SET(driver.loc_);
     default:
@@ -1456,6 +1457,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
 
 \"hostname-char-replacement\" {
     switch(driver.ctx_) {
+    case isc::dhcp::Parser4Context::DHCP4:
     case isc::dhcp::Parser4Context::DHCP_DDNS:
         return isc::dhcp::Dhcp4Parser::make_HOSTNAME_CHAR_REPLACEMENT(driver.loc_);
     default:
index 46901ce819bdc3826f967a1c12cdf9ff44f5add6..ec521c663cd54f07e8b89ba5e53e923b00a777a3 100644 (file)
@@ -477,6 +477,8 @@ global_param: valid_lifetime
             | t1_percent
             | t2_percent
             | loggers
+            | hostname_char_set
+            | hostname_char_replacement
             | unknown_map_entry
             ;
 
index 342dfd083023854c313c6e7deb0cd85c4ac500cc..9084da14e9df3ec001ba0670af3009a58b9774a3 100644 (file)
@@ -4627,8 +4627,8 @@ TEST_F(Dhcp6ParserTest, d2ClientConfig) {
     EXPECT_EQ(D2ClientConfig::RCM_WHEN_PRESENT, d2_client_config->getReplaceClientNameMode());
     EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
     EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
-    EXPECT_EQ("[^A-Za-z0-9_-]", d2_client_config->getHostnameCharSet());
-    EXPECT_EQ("x", d2_client_config->getHostnameCharReplacement());
+    EXPECT_EQ("[^A-Za-z0-9_-]", d2_client_config->getHostnameCharSet().get());
+    EXPECT_EQ("x", d2_client_config->getHostnameCharReplacement().get());
 }
 
 // This test checks the ability of the server to handle a configuration
index 8aa262b951d5fde64a0cad4fd32ee94c900b56b7..520cd3ce9b530c6d39f1f86abcaa7725aae7f0a4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
@@ -17,6 +17,7 @@
 using namespace std;
 using namespace isc::asiolink;
 using namespace isc::data;
+using namespace isc::util;
 
 namespace isc {
 namespace dhcp {
@@ -94,8 +95,8 @@ D2ClientConfig::D2ClientConfig(const  bool enable_updates,
                                const ReplaceClientNameMode replace_client_name_mode,
                                const std::string& generated_prefix,
                                const std::string& qualifying_suffix,
-                               const std::string& hostname_char_set,
-                               const std::string& hostname_char_replacement)
+                               Optional<std::string> hostname_char_set,
+                               Optional<std::string> hostname_char_replacement)
     : enable_updates_(enable_updates),
       server_ip_(server_ip),
       server_port_(server_port),
@@ -111,7 +112,8 @@ D2ClientConfig::D2ClientConfig(const  bool enable_updates,
       qualifying_suffix_(qualifying_suffix),
       hostname_char_set_(hostname_char_set),
       hostname_char_replacement_(hostname_char_replacement),
-      hostname_sanitizer_(0) {
+      hostname_sanitizer_(0),
+      fetch_globals_fn_(0) {
     validateContents();
 }
 
@@ -129,9 +131,10 @@ D2ClientConfig::D2ClientConfig()
       replace_client_name_mode_(stringToReplaceClientNameMode(DFT_REPLACE_CLIENT_NAME_MODE)),
       generated_prefix_(DFT_GENERATED_PREFIX),
       qualifying_suffix_(""),
-      hostname_char_set_(DFT_HOSTNAME_CHAR_SET),
-      hostname_char_replacement_(DFT_HOSTNAME_CHAR_SET),
-      hostname_sanitizer_(0) {
+      hostname_char_set_(DFT_HOSTNAME_CHAR_SET, true),
+      hostname_char_replacement_(DFT_HOSTNAME_CHAR_SET, true),
+      hostname_sanitizer_(0),
+      fetch_globals_fn_(0) {
     validateContents();
 }
 
@@ -170,10 +173,10 @@ D2ClientConfig::validateContents() {
                   << server_ip_.toText() << "/" << server_port_);
     }
 
-    if (!hostname_char_set_.empty()) {
+    if (!getHostnameCharSet().unspecified() && !getHostnameCharSet().empty()) {
         try {
-            hostname_sanitizer_.reset(new isc::util::str::StringSanitizer(hostname_char_set_,
-                                                                          hostname_char_replacement_));
+            hostname_sanitizer_.reset(new isc::util::str::StringSanitizer(getHostnameCharSet(),
+                                                                          getHostnameCharReplacement()));
         } catch (const std::exception& ex) {
             isc_throw(D2ClientError, "D2ClientConfig: hostname-char-set"
                       " is not a valid regular expression");
@@ -229,8 +232,8 @@ D2ClientConfig::toText() const {
                << replaceClientNameModeToString(replace_client_name_mode_)
                << ", generated-prefix: [" << generated_prefix_ << "]"
                << ", qualifying-suffix: [" << qualifying_suffix_ << "]"
-               << ", hostname-char-set: [" << hostname_char_set_ << "]"
-               << ", hostname-char-replacement: [" << hostname_char_replacement_ << "]";
+               << ", hostname-char-set: [" << getHostnameCharSet() << "]"
+               << ", hostname-char-replacement: [" << getHostnameCharReplacement() << "]";
     }
 
     return (stream.str());
@@ -269,9 +272,13 @@ D2ClientConfig::toElement() const {
     // Set generated-prefix
     result->set("generated-prefix", Element::create(generated_prefix_));
     // Set hostname-char-set
-    result->set("hostname-char-set", Element::create(hostname_char_set_));
+    if (!hostname_char_set_.unspecified()) {
+        result->set("hostname-char-set", Element::create(hostname_char_set_));
+    }
     // Set hostname-char-replacement
-    result->set("hostname-char-replacement", Element::create(hostname_char_replacement_));
+    if (!hostname_char_replacement_.unspecified()) {
+        result->set("hostname-char-replacement", Element::create(hostname_char_replacement_));
+    }
     return (result);
 }
 
index d8e001e60f1611b32fef27b525d4c664de093d85..bd88cb46317f4041c3962665305667b26df616e4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
@@ -18,6 +18,7 @@
 #include <dhcp_ddns/ncr_io.h>
 #include <exceptions/exceptions.h>
 #include <util/strutil.h>
+#include <util/optional.h>
 
 #include <boost/shared_ptr.hpp>
 
@@ -28,7 +29,6 @@
 namespace isc {
 namespace dhcp {
 
-
 /// An exception that is thrown if an error occurs while configuring
 /// the D2 DHCP DDNS client.
 class D2ClientError : public isc::Exception {
@@ -43,6 +43,10 @@ public:
         : isc::Exception(file, line, what) {}
 };
 
+/// @brief Callback function for @c D2ClientConfig that retrieves globally
+/// configured parameters.
+typedef std::function<data::ConstElementPtr()> FetchNetworkGlobalsFn;
+
 
 /// @brief Acts as a storage vault for D2 client configuration
 ///
@@ -97,7 +101,7 @@ public:
     /// @param generated_prefix Prefix to use when generating domain-names.
     /// @param qualifying_suffix Suffix to use to qualify partial domain-names.
     /// @param hostname_char_set regular expression string which describes invalid
-    /// characters to be scrubbed from client host names 
+    /// characters to be scrubbed from client host names
     /// @param hostname_char_replacement string of zero or more characters to
     /// replace invalid chars when sanitizing client host names
     ///
@@ -118,8 +122,8 @@ public:
                    const ReplaceClientNameMode replace_client_name_mode,
                    const std::string& generated_prefix,
                    const std::string& qualifying_suffix,
-                   const std::string& hostname_char_set,
-                   const std::string& hostname_char_replacement);
+                   util::Optional<std::string> hostname_char_set,
+                   util::Optional<std::string> hostname_char_replacement);
 
 
     /// @brief Default constructor
@@ -195,13 +199,35 @@ public:
     }
 
     /// @brief Return the char set regexp used to sanitize client hostnames.
-    const std::string& getHostnameCharSet() const {
-        return(hostname_char_set_);
-    }
+    util::Optional<std::string> getHostnameCharSet() const {
+        if (hostname_char_set_.unspecified() && fetch_globals_fn_) {
+            data::ConstElementPtr globals = fetch_globals_fn_();
+            if (globals && (globals->getType() == data::Element::map)) {
+                data::ConstElementPtr global_param =
+                    globals->get("hostname-char-set");
+                if (global_param) {
+                    return (global_param->stringValue());
+                }
+            }
+        }
+
+        return (hostname_char_set_);
+        }
 
     /// @brief Return the invalid char replacement used to sanitize client hostnames.
-    const std::string& getHostnameCharReplacement() const {
-        return(hostname_char_replacement_);
+    util::Optional<std::string> getHostnameCharReplacement() const {
+        if (hostname_char_replacement_.unspecified() && fetch_globals_fn_) {
+            data::ConstElementPtr globals = fetch_globals_fn_();
+            if (globals && (globals->getType() == data::Element::map)) {
+                data::ConstElementPtr global_param =
+                    globals->get("hostname-char-replacement");
+                if (global_param) {
+                    return (global_param->stringValue());
+                }
+            }
+        }
+
+        return (hostname_char_replacement_);
     }
 
     /// @brief Return pointer to compiled regular expression string sanitizer
@@ -210,6 +236,22 @@ public:
         return(hostname_sanitizer_);
     }
 
+    /// @brief Sets the optional callback function used to fetch globally
+    /// configured parameters.
+    ///
+    /// @param fetch_globals_fn Pointer to the function.
+    void setFetchGlobalsFn(FetchNetworkGlobalsFn fetch_globals_fn) {
+        fetch_globals_fn_ = fetch_globals_fn;
+    }
+
+    /// @brief Checks if the D2 client config is associated with a function
+    /// used to fetch globally configured parameters.
+    ///
+    /// @return true if it is associated, false otherwise.
+    bool hasFetchGlobalsFn() const {
+        return (static_cast<bool>(fetch_globals_fn_));
+    }
+
     /// @brief Compares two D2ClientConfigs for equality
     bool operator == (const D2ClientConfig& other) const;
 
@@ -306,14 +348,18 @@ private:
 
     /// @brief Regular expression describing invalid characters for client hostnames.
     /// If empty, host name scrubbing is not done.
-    std::string hostname_char_set_;
+    util::Optional<std::string> hostname_char_set_;
 
     /// @brief A string to replace invalid characters when scrubbing hostnames.
     /// Meaningful only if hostname_char_set_ is not empty.
-    std::string hostname_char_replacement_;
+    util::Optional<std::string> hostname_char_replacement_;
 
     /// @brief Pointer to compiled regular expression string sanitizer
     util::str::StringSanitizerPtr hostname_sanitizer_;
+
+    /// @brief Pointer to the optional callback used to fetch globally
+    /// configured parameters inherited to the @c D2ClientConfig object.
+    FetchNetworkGlobalsFn fetch_globals_fn_;
 };
 
 std::ostream&
index 57c03c3547a960f9bd5ecb0adcb8e6f05e7280cb..9e62161bceed01691260dff29e1ea494124a45d1 100644 (file)
@@ -653,7 +653,7 @@ SubnetConfigParser::createSubnet(ConstElementPtr params) {
     // In order to take advantage of the dynamic inheritance of global
     // parameters to a subnet we need to set a callback function for each
     // subnet to allow for fetching global parameters.
-     subnet_->setFetchGlobalsFn([]() -> ConstElementPtr {
+    subnet_->setFetchGlobalsFn([]() -> ConstElementPtr {
         return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
     });
 
@@ -1384,11 +1384,16 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
     std::string generated_prefix =
         getString(client_config, "generated-prefix");
 
-    std::string hostname_char_set =
-        getString(client_config, "hostname-char-set");
+    Optional<std::string> hostname_char_set(D2ClientConfig::DFT_HOSTNAME_CHAR_SET, true);
+    if (client_config->contains("hostname-char-set")) {
+        hostname_char_set = getString(client_config, "hostname-char-set");
+    }
 
-    std::string hostname_char_replacement =
-        getString(client_config, "hostname-char-replacement");
+    Optional<std::string> hostname_char_replacement(D2ClientConfig::DFT_HOSTNAME_CHAR_REPLACEMENT, true);
+    if (client_config->contains("hostname-char-replacement")) {
+        hostname_char_replacement =
+            getString(client_config, "hostname-char-replacement");
+    }
 
     // qualifying-suffix is the only parameter which has no default
     std::string qualifying_suffix = "";
@@ -1484,6 +1489,13 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
         new_config->setContext(user_context);
     }
 
+    // In order to take advantage of the dynamic inheritance of global
+    // parameters to a subnet we need to set a callback function for
+    // the d2 client config to allow for fetching global parameters.
+    new_config->setFetchGlobalsFn([]() -> ConstElementPtr {
+        return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
+    });
+
     return(new_config);
 }
 
@@ -1502,9 +1514,8 @@ const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = {
     { "override-no-update", Element::boolean, "false" },
     { "override-client-update", Element::boolean, "false" },
     { "replace-client-name", Element::string, "never" },
-    { "generated-prefix", Element::string, "myhost" },
-    { "hostname-char-set", Element::string, "" },
-    { "hostname-char-replacement", Element::string, "" }
+    { "generated-prefix", Element::string, "myhost" }
+    // hostname-char-set and hostname-char-replacement moved to global
     // qualifying-suffix has no default
 };
 
index d409cd55534c5d76c7d06fa9738703a6bf12e789..274f0cb5b447fc45f740967a10eeb5ab81fc10f2 100644 (file)
@@ -72,7 +72,9 @@ const SimpleKeywords SimpleParser4::GLOBAL4_PARAMETERS = {
     { "calculate-tee-times",          Element::boolean },
     { "t1-percent",                   Element::real },
     { "t2-percent",                   Element::real },
-    { "loggers",                      Element::list }
+    { "loggers",                      Element::list },
+    { "hostname-char-set",            Element::string },
+    { "hostname-char-replacement",    Element::string }
 };
 
 /// @brief This table defines default values for option definitions in DHCPv4.
@@ -103,20 +105,20 @@ const SimpleDefaults SimpleParser4::OPTION4_DEFAULTS = {
 /// in Dhcp4) are optional. If not defined, the following values will be
 /// used.
 const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = {
-    { "valid-lifetime",           Element::integer, "7200" },
-    { "decline-probation-period", Element::integer, "86400" }, // 24h
-    { "dhcp4o6-port",             Element::integer, "0" },
-    { "echo-client-id",           Element::boolean, "true" },
-    { "match-client-id",          Element::boolean, "true" },
-    { "authoritative",            Element::boolean, "false" },
-    { "next-server",              Element::string,  "0.0.0.0" },
-    { "server-hostname",          Element::string,  "" },
-    { "boot-file-name",           Element::string,  "" },
-    { "server-tag",               Element::string,  "" },
-    { "reservation-mode",         Element::string,  "all" },
-    { "calculate-tee-times",      Element::boolean, "false" },
-    { "t1-percent",               Element::real,    ".50" },
-    { "t2-percent",               Element::real,    ".875" }
+    { "valid-lifetime",            Element::integer, "7200" },
+    { "decline-probation-period",  Element::integer, "86400" }, // 24h
+    { "dhcp4o6-port",              Element::integer, "0" },
+    { "echo-client-id",            Element::boolean, "true" },
+    { "match-client-id",           Element::boolean, "true" },
+    { "authoritative",             Element::boolean, "false" },
+    { "next-server",               Element::string,  "0.0.0.0" },
+    { "server-hostname",           Element::string,  "" },
+    { "boot-file-name",            Element::string,  "" },
+    { "server-tag",                Element::string,  "" },
+    { "reservation-mode",          Element::string,  "all" },
+    { "calculate-tee-times",       Element::boolean, "false" },
+    { "t1-percent",                Element::real,    ".50" },
+    { "t2-percent",                Element::real,    ".875" }
 };
 
 /// @brief This table defines default values for each IPv4 subnet.