From: Thomas Markwalder Date: Mon, 23 Sep 2019 17:42:21 +0000 (-0400) Subject: [#35,!517] Modify D2ClientMgr functions to accept DdnsParams parameter X-Git-Tag: tmark-post-35-refactor~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b767f9446ec2657159e65cc0e2648336b0476bcd;p=thirdparty%2Fkea.git [#35,!517] Modify D2ClientMgr functions to accept DdnsParams parameter D2ClientMgr functions now get behavior parameters from a passed in structure instead of D2ClientMgr::d2_client_config_. src/lib/dhcpsrv/d2_client_cfg.h struct DdnsParams - new structure to convey request specific (i.e.scopable) Ddns params src/lib/dhcpsrv/alloc_engine.cc src/lib/dhcpsrv/alloc_engine.h Added ddns_params_ to ClientContext4/6 src/lib/dhcpsrv/d2_client_mgr.* D2ClientMgr::adjustFqdnFlags() D2ClientMgr::adjustDomainName() D2ClientMgr::analyzeFqdn() D2ClientMgr::generateFqdn() D2ClientMgr::qualifyName() - now accept DdnsParams instance as parameter src/lib/dhcpsrv/tests/d2_client_unittest.cc Reworked tests to use DdnsParams --- diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 9032974972..3584938652 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -430,7 +430,8 @@ namespace dhcp { AllocEngine::ClientContext6::ClientContext6() : query_(), fake_allocation_(false), subnet_(), host_subnet_(), duid_(), hwaddr_(), host_identifiers_(), hosts_(), fwd_dns_update_(false), - rev_dns_update_(false), hostname_(), callout_handle_(), ias_() { + rev_dns_update_(false), hostname_(), callout_handle_(), ias_(), + ddns_params_(new DdnsParams()) { } AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet, @@ -445,7 +446,7 @@ AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet, duid_(duid), hwaddr_(), host_identifiers_(), hosts_(), fwd_dns_update_(fwd_dns), rev_dns_update_(rev_dns), hostname_(hostname), callout_handle_(callout_handle), allocated_resources_(), new_leases_(), - ias_() { + ias_(), ddns_params_(new DdnsParams()) { // Initialize host identifiers. if (duid) { @@ -1156,7 +1157,8 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // the hostname as it is specified for the reservation. OptionPtr fqdn = ctx.query_->getOption(D6O_CLIENT_FQDN); ctx.hostname_ = CfgMgr::instance().getD2ClientMgr(). - qualifyName(host->getHostname(), static_cast(fqdn)); + qualifyName(host->getHostname(), *ctx.ddns_params_, + static_cast(fqdn)); } } } @@ -1228,7 +1230,8 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // the hostname as it is specified for the reservation. OptionPtr fqdn = ctx.query_->getOption(D6O_CLIENT_FQDN); ctx.hostname_ = CfgMgr::instance().getD2ClientMgr(). - qualifyName(host->getHostname(), static_cast(fqdn)); + qualifyName(host->getHostname(), *ctx.ddns_params_, + static_cast(fqdn)); } } @@ -1303,7 +1306,8 @@ AllocEngine::allocateGlobalReservedLeases6(ClientContext6& ctx, // the hostname as it is specified for the reservation. OptionPtr fqdn = ctx.query_->getOption(D6O_CLIENT_FQDN); ctx.hostname_ = CfgMgr::instance().getD2ClientMgr(). - qualifyName(ghost->getHostname(), static_cast(fqdn)); + qualifyName(ghost->getHostname(), *ctx.ddns_params_, + static_cast(fqdn)); } // If this is a real allocation, we may need to extend the lease @@ -1353,7 +1357,8 @@ AllocEngine::allocateGlobalReservedLeases6(ClientContext6& ctx, // the hostname as it is specified for the reservation. OptionPtr fqdn = ctx.query_->getOption(D6O_CLIENT_FQDN); ctx.hostname_ = CfgMgr::instance().getD2ClientMgr(). - qualifyName(ghost->getHostname(), static_cast(fqdn)); + qualifyName(ghost->getHostname(), *ctx.ddns_params_, + static_cast(fqdn)); } // Ok, let's create a new lease... @@ -3002,7 +3007,8 @@ AllocEngine::ClientContext4::ClientContext4() fwd_dns_update_(false), rev_dns_update_(false), hostname_(""), callout_handle_(), fake_allocation_(false), old_lease_(), new_lease_(), hosts_(), conflicting_lease_(), - query_(), host_identifiers_() { + query_(), host_identifiers_(), + ddns_params_(new DdnsParams()) { } AllocEngine::ClientContext4::ClientContext4(const Subnet4Ptr& subnet, @@ -3018,7 +3024,8 @@ AllocEngine::ClientContext4::ClientContext4(const Subnet4Ptr& subnet, fwd_dns_update_(fwd_dns_update), rev_dns_update_(rev_dns_update), hostname_(hostname), callout_handle_(), fake_allocation_(fake_allocation), old_lease_(), new_lease_(), - hosts_(), host_identifiers_() { + hosts_(), host_identifiers_(), + ddns_params_(new DdnsParams()) { // Initialize host identifiers. if (hwaddr) { diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index fee5e23e27..89e5765ab0 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -552,6 +553,9 @@ public: /// @brief Container holding IA specific contexts. std::vector ias_; + /// @brief Holds scoped DDNS behavioral parameters + DdnsParamsPtr ddns_params_; + /// @brief Convenience method adding allocated prefix or address. /// /// @param prefix Prefix or address. @@ -1319,6 +1323,9 @@ public: /// received by the server. IdentifierList host_identifiers_; + /// @brief Holds scoped DDNS behavioral parameters + DdnsParamsPtr ddns_params_; + /// @brief Convenience function adding host identifier into /// @ref host_identifiers_ list. /// diff --git a/src/lib/dhcpsrv/d2_client_cfg.h b/src/lib/dhcpsrv/d2_client_cfg.h index 4fdec9c81c..d6f1972dd8 100644 --- a/src/lib/dhcpsrv/d2_client_cfg.h +++ b/src/lib/dhcpsrv/d2_client_cfg.h @@ -369,6 +369,41 @@ operator<<(std::ostream& os, const D2ClientConfig& config); /// @brief Defines a pointer for D2ClientConfig instances. typedef boost::shared_ptr D2ClientConfigPtr; +/// @Brief Convenience container for conveying DDNS behaviorial parameters +/// It is intended to be populated per Packet exchange and passed into +/// functions that require them +struct DdnsParams { + DdnsParams() : + enable_updates_(false), override_no_update_(false), override_client_update_(false), + replace_client_name_mode_(D2ClientConfig::RCM_NEVER), + generated_prefix_(""), qualifying_suffix_("") {}; + + /// @brief Indicates whether or not DHCP DDNS updating is enabled. + bool enable_updates_; + + /// @brief Should Kea perform updates, even if client requested no updates. + /// Overrides the client request for no updates via the N flag. + bool override_no_update_; + + /// @brief Should Kea perform updates, even if client requested delegation. + bool override_client_update_; + + /// @brief How Kea should handle the domain-name supplied by the client. + D2ClientConfig::ReplaceClientNameMode replace_client_name_mode_; + + /// @brief Prefix Kea should use when generating domain-names. + std::string generated_prefix_; + + /// @brief Suffix Kea should use when to qualify partial domain-names. + std::string qualifying_suffix_; + + /// @brief Pointer to compiled regular expression string sanitizer + util::str::StringSanitizerPtr hostname_sanitizer_; +}; + +/// @brief Defines a pointer for DdnsParams instances. +typedef boost::shared_ptr DdnsParamsPtr; + } // namespace isc } // namespace dhcp diff --git a/src/lib/dhcpsrv/d2_client_mgr.cc b/src/lib/dhcpsrv/d2_client_mgr.cc index 162eaf5443..9712403acf 100644 --- a/src/lib/dhcpsrv/d2_client_mgr.cc +++ b/src/lib/dhcpsrv/d2_client_mgr.cc @@ -114,7 +114,8 @@ D2ClientMgr::getD2ClientConfig() const { void D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n, - bool& server_s, bool& server_n) const { + bool& server_s, bool& server_n, + const DdnsParams& ddns_params) const { // Per RFC 4702 & 4704, the client N and S flags allow the client to // request one of three options: // @@ -132,27 +133,27 @@ D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n, switch (mask) { case 0: - if (!d2_client_config_->getEnableUpdates()) { + if (!ddns_params.enable_updates_) { server_s = false; server_n = true; } else { // If updates are enabled and we are overriding client delegation // then S flag should be true. N-flag should be false. - server_s = d2_client_config_->getOverrideClientUpdate(); + server_s = ddns_params.override_client_update_; server_n = false; } break; case 1: - server_s = d2_client_config_->getEnableUpdates(); + server_s = ddns_params.enable_updates_; server_n = !server_s; break; case 2: // If updates are enabled and we are overriding "no updates" then // S flag should be true. - server_s = (d2_client_config_->getEnableUpdates() && - d2_client_config_->getOverrideNoUpdate()); + server_s = (ddns_params.enable_updates_ && + ddns_params.override_no_update_); server_n = !server_s; break; @@ -166,31 +167,33 @@ D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n, std::string D2ClientMgr::generateFqdn(const asiolink::IOAddress& address, + const DdnsParams& ddns_params, const bool trailing_dot) const { std::string hostname = address.toText(); std::replace(hostname.begin(), hostname.end(), (address.isV4() ? '.' : ':'), '-'); std::ostringstream gen_name; - gen_name << d2_client_config_->getGeneratedPrefix() << "-" << hostname; - return (qualifyName(gen_name.str(), trailing_dot)); + gen_name << ddns_params.generated_prefix_ << "-" << hostname; + return (qualifyName(gen_name.str(), ddns_params, trailing_dot)); } std::string D2ClientMgr::qualifyName(const std::string& partial_name, + const DdnsParams& ddns_params, const bool trailing_dot) const { std::ostringstream gen_name; gen_name << partial_name; - if (!d2_client_config_->getQualifyingSuffix().empty()) { + if (!ddns_params.qualifying_suffix_.empty()) { std::string str = gen_name.str(); size_t len = str.length(); if ((len > 0) && (str[len - 1] != '.')) { gen_name << "."; } - gen_name << d2_client_config_->getQualifyingSuffix(); + gen_name << ddns_params.qualifying_suffix_; } std::string str = gen_name.str(); diff --git a/src/lib/dhcpsrv/d2_client_mgr.h b/src/lib/dhcpsrv/d2_client_mgr.h index ca2d1db339..cc655b4c12 100644 --- a/src/lib/dhcpsrv/d2_client_mgr.h +++ b/src/lib/dhcpsrv/d2_client_mgr.h @@ -147,11 +147,12 @@ public: /// @param client_n N Flag from the client's FQDN /// @param server_s [out] S Flag for the server's FQDN /// @param server_n [out] N Flag for the server's FQDN + /// @param ddns_params DDNS behaviorial configuration parameters /// /// @throw isc::BadValue if client_s and client_n are both 1 as this is /// an invalid combination per RFCs. void analyzeFqdn(const bool client_s, const bool client_n, bool& server_s, - bool& server_n) const; + bool& server_n, const DdnsParams& ddns_params) const; /// @brief Builds a FQDN based on the configuration and given IP address. /// @@ -166,11 +167,13 @@ public: /// ('.' for IPv4 or ':' for IPv6) replaced with a hyphen, '-'. /// /// @param address IP address from which to derive the name (IPv4 or IPv6) + /// @param ddns_params DDNS behaviorial configuration parameters /// @param trailing_dot A boolean value which indicates whether trailing /// dot should be appended (if true) or not (false). /// /// @return std::string containing the generated name. std::string generateFqdn(const asiolink::IOAddress& address, + const DdnsParams& ddns_params, const bool trailing_dot = true) const; /// @brief Adds a qualifying suffix to a given domain name @@ -181,6 +184,7 @@ public: /// .. /// /// @param partial_name domain name to qualify + /// @param ddns_params DDNS behaviorial configuration parameters /// @param trailing_dot A boolean value which when true guarantees the /// result will end with a "." and when false that the result will not /// end with a "." Note that this rule is applied even if the qualifying @@ -188,6 +192,7 @@ public: /// /// @return std::string containing the qualified name. std::string qualifyName(const std::string& partial_name, + const DdnsParams& ddns_params, const bool trailing_dot) const; /// @brief Set server FQDN flags based on configuration and a given FQDN @@ -199,10 +204,12 @@ public: /// /// @param fqdn FQDN option from which to read client (inbound) flags /// @param fqdn_resp FQDN option to update with the server (outbound) flags + /// @param ddns_params DDNS behaviorial configuration parameters /// @tparam T FQDN Option class containing the FQDN data such as /// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn template - void adjustFqdnFlags(const T& fqdn, T& fqdn_resp); + void adjustFqdnFlags(const T& fqdn, T& fqdn_resp, + const DdnsParams& ddns_params); /// @brief Get directional update flags based on server FQDN flags /// @@ -248,10 +255,12 @@ public: /// /// @param fqdn FQDN option from which to get client (inbound) name /// @param fqdn_resp FQDN option to update with the adjusted name + /// @param ddns_params DDNS behaviorial configuration parameters /// @tparam T FQDN Option class containing the FQDN data such as /// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn template - void adjustDomainName(const T& fqdn, T& fqdn_resp); + void adjustDomainName(const T& fqdn, T& fqdn_resp, + const DdnsParams& ddns_params); /// @brief Enables sending NameChangeRequests to kea-dhcp-ddns /// @@ -435,11 +444,11 @@ private: template void -D2ClientMgr::adjustFqdnFlags(const T& fqdn, T& fqdn_resp) { +D2ClientMgr::adjustFqdnFlags(const T& fqdn, T& fqdn_resp, const DdnsParams& ddns_params) { bool server_s = false; bool server_n = false; analyzeFqdn(fqdn.getFlag(T::FLAG_S), fqdn.getFlag(T::FLAG_N), - server_s, server_n); + server_s, server_n, ddns_params); // Reset the flags to zero to avoid triggering N and S both 1 check. fqdn_resp.resetFlags(); @@ -462,18 +471,18 @@ D2ClientMgr::getUpdateDirections(const T& fqdn_resp, template void -D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) { +D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp, const DdnsParams& ddns_params) { // If we're configured to replace it or the supplied name is blank // set the response name to blank. - if ((d2_client_config_->getReplaceClientNameMode() == D2ClientConfig::RCM_ALWAYS || - d2_client_config_->getReplaceClientNameMode() == D2ClientConfig::RCM_WHEN_PRESENT) || + if ((ddns_params.replace_client_name_mode_ == D2ClientConfig::RCM_ALWAYS || + ddns_params.replace_client_name_mode_ == D2ClientConfig::RCM_WHEN_PRESENT) || fqdn.getDomainName().empty()) { fqdn_resp.setDomainName("", T::PARTIAL); } else { // Sanitize the name the client sent us, if we're configured to do so. std::string client_name = fqdn.getDomainName(); - if (d2_client_config_->getHostnameSanitizer()) { + if (ddns_params.hostname_sanitizer_) { // We need the raw text form, so we can replace escaped chars dns::Name tmp(client_name); std::string raw_name = tmp.toRawText(); @@ -490,7 +499,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) { ss << "."; } - ss << d2_client_config_->getHostnameSanitizer()->scrub(*label); + ss << ddns_params.hostname_sanitizer_->scrub(*label); } client_name = ss.str(); @@ -498,7 +507,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) { // If the supplied name is partial, qualify it by adding the suffix. if (fqdn.getDomainNameType() == T::PARTIAL) { - fqdn_resp.setDomainName(qualifyName(client_name,true), T::FULL); + fqdn_resp.setDomainName(qualifyName(client_name, ddns_params, true), T::FULL); } else { fqdn_resp.setDomainName(client_name, T::FULL); @@ -506,6 +515,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) { } } + /// @brief Defines a pointer for D2ClientMgr instances. typedef boost::shared_ptr D2ClientMgrPtr; diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index a9c20aa85e..a484208c5c 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -1440,11 +1440,13 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { // qualifying-suffix is the only parameter which has no default std::string qualifying_suffix = ""; +#if 0 bool found_qualifying_suffix = false; if (client_config->contains("qualifying-suffix")) { qualifying_suffix = getString(client_config, "qualifying-suffix"); found_qualifying_suffix = true; } +#endif IOAddress sender_ip(0); if (sender_ip_str.empty()) { @@ -1461,6 +1463,7 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { } } +#if 0 // Qualifying-suffix is required when updates are enabled if (enable_updates && !found_qualifying_suffix) { isc_throw(DhcpConfigError, @@ -1468,6 +1471,7 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { "updates are enabled (" << client_config->getPosition() << ")"); } +#endif // Now we check for logical errors. This repeats what is done in // D2ClientConfig::validate(), but doing it here permits us to diff --git a/src/lib/dhcpsrv/tests/d2_client_unittest.cc b/src/lib/dhcpsrv/tests/d2_client_unittest.cc index e1b59a4429..b05db835a2 100644 --- a/src/lib/dhcpsrv/tests/d2_client_unittest.cc +++ b/src/lib/dhcpsrv/tests/d2_client_unittest.cc @@ -492,29 +492,10 @@ TEST(D2ClientMgr, analyzeFqdnInvalidCombination) { bool server_s = false; bool server_n = false; - // Create disabled configuration. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig())); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_FALSE(mgr.ddnsEnabled()); + DdnsParams ddns_params; // client S=1 N=1 is invalid. analyzeFqdn should throw. - ASSERT_THROW(mgr.analyzeFqdn(true, true, server_s, server_n), - isc::BadValue); - - // Create enabled configuration with all controls off (no overrides). - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_NEVER, - "pre-fix", "suf-fix", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_TRUE(mgr.ddnsEnabled()); - - // client S=1 N=1 is invalid. analyzeFqdn should throw. - ASSERT_THROW(mgr.analyzeFqdn(true, true, server_s, server_n), + ASSERT_THROW(mgr.analyzeFqdn(true, true, server_s, server_n, ddns_params), isc::BadValue); } @@ -526,30 +507,25 @@ TEST(D2ClientMgr, analyzeFqdnEnabledNoOverrides) { bool server_n = false; // Create enabled configuration with all controls off (no overrides). - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_NEVER, - "pre-fix", "suf-fix", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_TRUE(mgr.ddnsEnabled()); - ASSERT_FALSE(cfg->getOverrideClientUpdate()); - ASSERT_FALSE(cfg->getOverrideNoUpdate()); + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = ""; + ddns_params.qualifying_suffix_ = ""; // client S=0 N=0 means client wants to do forward update. // server S should be 0 (server is not doing forward updates) // and server N should be 0 (server doing reverse updates) - mgr.analyzeFqdn(false, false, server_s, server_n); + mgr.analyzeFqdn(false, false, server_s, server_n, ddns_params); EXPECT_FALSE(server_s); EXPECT_FALSE(server_n); // client S=1 N=0 means client wants server to do forward update. // server S should be 1 (server is doing forward updates) // and server N should be 0 (server doing updates) - mgr.analyzeFqdn(true, false, server_s, server_n); + mgr.analyzeFqdn(true, false, server_s, server_n, ddns_params); EXPECT_TRUE(server_s); EXPECT_FALSE(server_n); @@ -557,7 +533,7 @@ TEST(D2ClientMgr, analyzeFqdnEnabledNoOverrides) { // client S=0 N=1 means client wants no one to do forward updates. // server S should be 0 (server is not forward updates) // and server N should be 1 (server is not doing any updates) - mgr.analyzeFqdn(false, true, server_s, server_n); + mgr.analyzeFqdn(false, true, server_s, server_n, ddns_params); EXPECT_FALSE(server_s); EXPECT_TRUE(server_n); } @@ -569,38 +545,33 @@ TEST(D2ClientMgr, analyzeFqdnEnabledOverrideNoUpdate) { bool server_s = false; bool server_n = false; - // Create enabled configuration with OVERRIDE_NO_UPDATE on. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - true, false, D2ClientConfig::RCM_NEVER, - "pre-fix", "suf-fix", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_TRUE(mgr.ddnsEnabled()); - ASSERT_TRUE(cfg->getOverrideNoUpdate()); - ASSERT_FALSE(cfg->getOverrideClientUpdate()); + // Create enabled configuration with override-no-update true. + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = true; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = ""; + ddns_params.qualifying_suffix_ = ""; // client S=0 N=0 means client wants to do forward update. // server S should be 0 (server is not doing forward updates) // and server N should be 0 (server is doing reverse updates) - mgr.analyzeFqdn(false, false, server_s, server_n); + mgr.analyzeFqdn(false, false, server_s, server_n, ddns_params); EXPECT_FALSE(server_s); EXPECT_FALSE(server_n); // client S=1 N=0 means client wants server to do forward update. // server S should be 1 (server is doing forward updates) // and server N should be 0 (server doing updates) - mgr.analyzeFqdn(true, false, server_s, server_n); + mgr.analyzeFqdn(true, false, server_s, server_n, ddns_params); EXPECT_TRUE(server_s); EXPECT_FALSE(server_n); // client S=0 N=1 means client wants no one to do forward updates. // server S should be 1 (server is doing forward updates) // and server N should be 0 (server is doing updates) - mgr.analyzeFqdn(false, true, server_s, server_n); + mgr.analyzeFqdn(false, true, server_s, server_n, ddns_params); EXPECT_TRUE(server_s); EXPECT_FALSE(server_n); } @@ -612,38 +583,34 @@ TEST(D2ClientMgr, analyzeFqdnEnabledOverrideClientUpdate) { bool server_s = false; bool server_n = false; - // Create enabled configuration with OVERRIDE_CLIENT_UPDATE on. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "pre-fix", "suf-fix", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_TRUE(mgr.ddnsEnabled()); - ASSERT_FALSE(cfg->getOverrideNoUpdate()); - ASSERT_TRUE(cfg->getOverrideClientUpdate()); + // Create enabled configuration with override-client-update true. + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = true; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = ""; + ddns_params.qualifying_suffix_ = ""; + // client S=0 N=0 means client wants to do forward update. // server S should be 1 (server is doing forward updates) // and server N should be 0 (server doing updates) - mgr.analyzeFqdn(false, false, server_s, server_n); + mgr.analyzeFqdn(false, false, server_s, server_n, ddns_params); EXPECT_TRUE(server_s); EXPECT_FALSE(server_n); // client S=1 N=0 means client wants server to do forward update. // server S should be 1 (server is doing forward updates) // and server N should be 0 (server doing updates) - mgr.analyzeFqdn(true, false, server_s, server_n); + mgr.analyzeFqdn(true, false, server_s, server_n, ddns_params); EXPECT_TRUE(server_s); EXPECT_FALSE(server_n); // client S=0 N=1 means client wants no one to do forward updates. // server S should be 0 (server is not forward updates) // and server N should be 1 (server is not doing any updates) - mgr.analyzeFqdn(false, true, server_s, server_n); + mgr.analyzeFqdn(false, true, server_s, server_n, ddns_params); EXPECT_FALSE(server_s); EXPECT_TRUE(server_n); } @@ -656,19 +623,14 @@ TEST(D2ClientMgr, adjustFqdnFlagsV4) { Option4ClientFqdnPtr request; Option4ClientFqdnPtr response; - // Create enabled configuration and override-no-update on. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - true, false, D2ClientConfig::RCM_NEVER, - "pre-fix", "suf-fix", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_TRUE(mgr.ddnsEnabled()); - ASSERT_TRUE(cfg->getOverrideNoUpdate()); - ASSERT_FALSE(cfg->getOverrideClientUpdate()); + // Create enabled configuration with override-no-update true. + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = true; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = ""; + ddns_params.qualifying_suffix_ = ""; // client S=0 N=0 means client wants to do forward update. // server S should be 0 (server is not doing forward updates) @@ -679,7 +641,7 @@ TEST(D2ClientMgr, adjustFqdnFlagsV4) { response.reset(new Option4ClientFqdn(*request)); response->resetFlags(); - mgr.adjustFqdnFlags(*request, *response); + mgr.adjustFqdnFlags(*request, *response, ddns_params); EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_S)); EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_N)); EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_O)); @@ -694,7 +656,7 @@ TEST(D2ClientMgr, adjustFqdnFlagsV4) { response.reset(new Option4ClientFqdn(*request)); response->resetFlags(); - mgr.adjustFqdnFlags(*request, *response); + mgr.adjustFqdnFlags(*request, *response, ddns_params); EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_S)); EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_N)); EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_O)); @@ -709,7 +671,7 @@ TEST(D2ClientMgr, adjustFqdnFlagsV4) { response.reset(new Option4ClientFqdn(*request)); response->resetFlags(); - mgr.adjustFqdnFlags(*request, *response); + mgr.adjustFqdnFlags(*request, *response, ddns_params); EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_S)); EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_N)); EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_O)); @@ -754,100 +716,64 @@ TEST(D2ClientMgr, updateDirectionsV4) { /// @brief Tests the qualifyName method's ability to construct FQDNs TEST(D2ClientMgr, qualifyName) { D2ClientMgr mgr; - - // Create enabled configuration. - D2ClientConfigPtr cfg; - - //append suffix and dot - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - - // Verify that the qualifying suffix gets appended with trailing dot added. + bool do_not_dot = false; + bool do_dot = true; + + // Create enabled configuration + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = "prefix"; + ddns_params.qualifying_suffix_ = "suffix.com"; + + // Verify that the qualifying suffix gets appended with a trailing dot added. std::string partial_name = "somehost"; - std::string qualified_name = mgr.qualifyName(partial_name, true); + std::string qualified_name = mgr.qualifyName(partial_name, ddns_params, do_dot); EXPECT_EQ("somehost.suffix.com.", qualified_name); - - //append suffix but dot - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); + // Verify that the qualifying suffix gets appended without a trailing dot. partial_name = "somehost"; - qualified_name = mgr.qualifyName(partial_name, false); //false means no dot + qualified_name = mgr.qualifyName(partial_name, ddns_params, do_not_dot); EXPECT_EQ("somehost.suffix.com", qualified_name); - - //append no suffix and not dot - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "prefix", "", "", ""))); //empty suffix - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); + // Verify that an empty suffix and false flag, does not change the name + ddns_params.qualifying_suffix_ = ""; partial_name = "somehost"; - qualified_name = mgr.qualifyName(partial_name, false); //false means no dot + qualified_name = mgr.qualifyName(partial_name, ddns_params, do_not_dot); EXPECT_EQ("somehost", qualified_name); - // Verify that the qualifying suffix gets appended with trailing dot added. - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "prefix", "hasdot.com.", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - - // Verify that the qualifying suffix gets appended without dot added. - qualified_name = mgr.qualifyName(partial_name, true); + // Verify that a qualifying suffix that already has a trailing + // dot gets appended without doubling the dot. + ddns_params.qualifying_suffix_ = "hasdot.com."; + qualified_name = mgr.qualifyName(partial_name, ddns_params, do_dot); EXPECT_EQ("somehost.hasdot.com.", qualified_name); // Verify that the qualifying suffix gets appended without an // extraneous dot when partial_name ends with a "." - qualified_name = mgr.qualifyName("somehost.", true); + qualified_name = mgr.qualifyName("somehost.", ddns_params, do_dot); EXPECT_EQ("somehost.hasdot.com.", qualified_name); - // Reconfigure to a "" suffix - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "prefix", "", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - // Verify that a name with a trailing dot does not get an extraneous // dot when the suffix is blank - qualified_name = mgr.qualifyName("somehost.", true); + ddns_params.qualifying_suffix_ = ""; + qualified_name = mgr.qualifyName("somehost.", ddns_params, do_dot); EXPECT_EQ("somehost.", qualified_name); // Verify that a name with no trailing dot gets just a dot when the // suffix is blank - qualified_name = mgr.qualifyName("somehost", true); + qualified_name = mgr.qualifyName("somehost", ddns_params, do_dot); EXPECT_EQ("somehost.", qualified_name); // Verify that a name with no trailing dot does not get dotted when the // suffix is blank and trailing dot is false - qualified_name = mgr.qualifyName("somehost", false); + qualified_name = mgr.qualifyName("somehost", ddns_params, do_not_dot); EXPECT_EQ("somehost", qualified_name); // Verify that a name with trailing dot gets "undotted" when the // suffix is blank and trailing dot is false - qualified_name = mgr.qualifyName("somehost.", false); + qualified_name = mgr.qualifyName("somehost.", ddns_params, do_not_dot); EXPECT_EQ("somehost", qualified_name); } @@ -856,214 +782,260 @@ TEST(D2ClientMgr, qualifyName) { /// @brief Tests the generateFdqn method's ability to construct FQDNs TEST(D2ClientMgr, generateFqdn) { D2ClientMgr mgr; + bool do_dot = true; - // Create enabled configuration. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, true, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); + // Create enabled configuration + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = "prefix"; + ddns_params.qualifying_suffix_ = "suffix.com"; // Verify that it works with an IPv4 address. asiolink::IOAddress v4address("192.0.2.75"); - EXPECT_EQ("prefix-192-0-2-75.suffix.com.", mgr.generateFqdn(v4address,true)); + EXPECT_EQ("prefix-192-0-2-75.suffix.com.", + mgr.generateFqdn(v4address, ddns_params, do_dot)); // Verify that it works with an IPv6 address. asiolink::IOAddress v6address("2001:db8::2"); - EXPECT_EQ("prefix-2001-db8--2.suffix.com.", mgr.generateFqdn(v6address,true)); + EXPECT_EQ("prefix-2001-db8--2.suffix.com.", + mgr.generateFqdn(v6address, ddns_params, do_dot)); // Create a disabled config. - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig())); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); + ddns_params.enable_updates_ = false; // Verify names generate properly with a disabled configuration. - EXPECT_EQ("myhost-192-0-2-75.", mgr.generateFqdn(v4address,true)); - EXPECT_EQ("myhost-2001-db8--2.", mgr.generateFqdn(v6address,true)); + EXPECT_EQ("prefix-192-0-2-75.suffix.com.", + mgr.generateFqdn(v4address, ddns_params, do_dot)); + EXPECT_EQ("prefix-2001-db8--2.suffix.com.", + mgr.generateFqdn(v6address, ddns_params, do_dot)); } /// @brief Tests adjustDomainName template method with Option4ClientFqdn TEST(D2ClientMgr, adjustDomainNameV4) { D2ClientMgr mgr; - Option4ClientFqdnPtr request; - Option4ClientFqdnPtr response; - // Create enabled configuration. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_EQ(D2ClientConfig::RCM_NEVER, cfg->getReplaceClientNameMode()); + // Create enabled configuration + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = "prefix"; + ddns_params.qualifying_suffix_ = "suffix.com"; - // replace-client-name is false, client passes in empty fqdn - // response domain should be empty/partial. - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - "", Option4ClientFqdn::PARTIAL)); - response.reset(new Option4ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType()); - - - // replace-client-name is false, client passes in a partial fqdn - // response should contain client's name plus the qualifying suffix. - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - "myhost", Option4ClientFqdn::PARTIAL)); - response.reset(new Option4ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("myhost.suffix.com.", response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::FULL, response->getDomainNameType()); - - - // replace-client-name is false, client passes in a full fqdn - // response domain should not be altered. - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - "myhost.example.com.", - Option4ClientFqdn::FULL)); - response.reset(new Option4ClientFqdn(*request)); - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("myhost.example.com.", response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::FULL, response->getDomainNameType()); - - // Create enabled configuration. - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_WHEN_PRESENT, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_EQ(D2ClientConfig::RCM_WHEN_PRESENT, cfg->getReplaceClientNameMode()); - - // replace-client-name is true, client passes in empty fqdn - // response domain should be empty/partial. - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - "", Option4ClientFqdn::PARTIAL)); - response.reset(new Option4ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType()); - - // replace-client-name is true, client passes in a partial fqdn - // response domain should be empty/partial. - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - "myhost", Option4ClientFqdn::PARTIAL)); - response.reset(new Option4ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType()); + struct Scenario { + std::string description_; + D2ClientConfig::ReplaceClientNameMode mode_; + std::string client_name_; + Option4ClientFqdn::DomainNameType client_name_type_; + std::string expected_name_; + Option4ClientFqdn::DomainNameType expected_name_type_; + }; + std::vector scenarios = { + { + "RCM_NEVER #1, empty client name", + D2ClientConfig::RCM_NEVER, + "", Option4ClientFqdn::PARTIAL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_NEVER #2, partial client name", + D2ClientConfig::RCM_NEVER, + "myhost", Option4ClientFqdn::PARTIAL, + "myhost.suffix.com.", Option4ClientFqdn::FULL + }, + { + "RCM_NEVER #3, full client name", + D2ClientConfig::RCM_NEVER, + "myhost.example.com.", Option4ClientFqdn::FULL, + "myhost.example.com.", Option4ClientFqdn::FULL + }, + { + "RCM_ALWAYS #1, empty client name", + D2ClientConfig::RCM_ALWAYS, + "", Option4ClientFqdn::PARTIAL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_ALWAYS #2, partial client name", + D2ClientConfig::RCM_ALWAYS, + "myhost", Option4ClientFqdn::PARTIAL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_ALWAYS #3, full client name", + D2ClientConfig::RCM_ALWAYS, + "myhost.example.com.", Option4ClientFqdn::FULL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_PRESENT #1, empty client name", + D2ClientConfig::RCM_WHEN_PRESENT, + "", Option4ClientFqdn::PARTIAL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_PRESENT #2, partial client name", + D2ClientConfig::RCM_WHEN_PRESENT, + "myhost", Option4ClientFqdn::PARTIAL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_PRESENT #3, full client name", + D2ClientConfig::RCM_WHEN_PRESENT, + "myhost.example.com.", Option4ClientFqdn::FULL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_NOT_PRESENT #1, empty client name", + D2ClientConfig::RCM_WHEN_NOT_PRESENT, + "", Option4ClientFqdn::PARTIAL, + "", Option4ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_NOT_PRESENT #2, partial client name", + D2ClientConfig::RCM_WHEN_NOT_PRESENT, + "myhost", Option4ClientFqdn::PARTIAL, + "myhost.suffix.com.", Option4ClientFqdn::FULL + }, + { + "RCM_WHEN_NOT_PRESENT #3, full client name", + D2ClientConfig::RCM_WHEN_NOT_PRESENT, + "myhost.example.com.", Option4ClientFqdn::FULL, + "myhost.example.com.", Option4ClientFqdn::FULL, + } + }; - // replace-client-name is true, client passes in a full fqdn - // response domain should be empty/partial. - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - "myhost.example.com.", - Option4ClientFqdn::FULL)); - response.reset(new Option4ClientFqdn(*request)); - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType()); + for (auto scenario : scenarios) { + SCOPED_TRACE(scenario.description_); + { + ddns_params.replace_client_name_mode_ = scenario.mode_; + Option4ClientFqdn request (0, Option4ClientFqdn::RCODE_CLIENT(), + scenario.client_name_, + scenario.client_name_type_); + + Option4ClientFqdn response(request); + mgr.adjustDomainName(request, response, ddns_params); + EXPECT_EQ(scenario.expected_name_, response.getDomainName()); + EXPECT_EQ(scenario.expected_name_type_, response.getDomainNameType()); + } + } } /// @brief Tests adjustDomainName template method with Option6ClientFqdn TEST(D2ClientMgr, adjustDomainNameV6) { D2ClientMgr mgr; - Option6ClientFqdnPtr request; - Option6ClientFqdnPtr response; - // Create enabled configuration. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_EQ(D2ClientConfig::RCM_NEVER, cfg->getReplaceClientNameMode()); - - // replace-client-name is false, client passes in empty fqdn - // response domain should be empty/partial. - request.reset(new Option6ClientFqdn(0, "", Option6ClientFqdn::PARTIAL)); - response.reset(new Option6ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType()); - - // replace-client-name is false, client passes in a partial fqdn - // response should contain client's name plus the qualifying suffix. - request.reset(new Option6ClientFqdn(0, "myhost", - Option6ClientFqdn::PARTIAL)); - response.reset(new Option6ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("myhost.suffix.com.", response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::FULL, response->getDomainNameType()); - - - // replace-client-name is false, client passes in a full fqdn - // response domain should not be altered. - request.reset(new Option6ClientFqdn(0, "myhost.example.com.", - Option6ClientFqdn::FULL)); - response.reset(new Option6ClientFqdn(*request)); - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("myhost.example.com.", response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::FULL, response->getDomainNameType()); + // Create enabled configuration + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = "prefix"; + ddns_params.qualifying_suffix_ = "suffix.com"; - // Create enabled configuration. - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_WHEN_PRESENT, - "prefix", "suffix.com", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_EQ(D2ClientConfig::RCM_WHEN_PRESENT, cfg->getReplaceClientNameMode()); - - // replace-client-name is true, client passes in empty fqdn - // response domain should be empty/partial. - request.reset(new Option6ClientFqdn(0, "", Option6ClientFqdn::PARTIAL)); - response.reset(new Option6ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType()); - - // replace-client-name is true, client passes in a partial fqdn - // response domain should be empty/partial. - request.reset(new Option6ClientFqdn(0, "myhost", - Option6ClientFqdn::PARTIAL)); - response.reset(new Option6ClientFqdn(*request)); - - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType()); + struct Scenario { + std::string description_; + D2ClientConfig::ReplaceClientNameMode mode_; + std::string client_name_; + Option6ClientFqdn::DomainNameType client_name_type_; + std::string expected_name_; + Option6ClientFqdn::DomainNameType expected_name_type_; + }; + std::vector scenarios = { + { + "RCM_NEVER #1, empty client name", + D2ClientConfig::RCM_NEVER, + "", Option6ClientFqdn::PARTIAL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_NEVER #2, partial client name", + D2ClientConfig::RCM_NEVER, + "myhost", Option6ClientFqdn::PARTIAL, + "myhost.suffix.com.", Option6ClientFqdn::FULL + }, + { + "RCM_NEVER #3, full client name", + D2ClientConfig::RCM_NEVER, + "myhost.example.com.", Option6ClientFqdn::FULL, + "myhost.example.com.", Option6ClientFqdn::FULL + }, + { + "RCM_ALWAYS #1, empty client name", + D2ClientConfig::RCM_ALWAYS, + "", Option6ClientFqdn::PARTIAL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_ALWAYS #2, partial client name", + D2ClientConfig::RCM_ALWAYS, + "myhost", Option6ClientFqdn::PARTIAL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_ALWAYS #3, full client name", + D2ClientConfig::RCM_ALWAYS, + "myhost.example.com.", Option6ClientFqdn::FULL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_PRESENT #1, empty client name", + D2ClientConfig::RCM_WHEN_PRESENT, + "", Option6ClientFqdn::PARTIAL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_PRESENT #2, partial client name", + D2ClientConfig::RCM_WHEN_PRESENT, + "myhost", Option6ClientFqdn::PARTIAL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_PRESENT #3, full client name", + D2ClientConfig::RCM_WHEN_PRESENT, + "myhost.example.com.", Option6ClientFqdn::FULL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_NOT_PRESENT #1, empty client name", + D2ClientConfig::RCM_WHEN_NOT_PRESENT, + "", Option6ClientFqdn::PARTIAL, + "", Option6ClientFqdn::PARTIAL + }, + { + "RCM_WHEN_NOT_PRESENT #2, partial client name", + D2ClientConfig::RCM_WHEN_NOT_PRESENT, + "myhost", Option6ClientFqdn::PARTIAL, + "myhost.suffix.com.", Option6ClientFqdn::FULL + }, + { + "RCM_WHEN_NOT_PRESENT #3, full client name", + D2ClientConfig::RCM_WHEN_NOT_PRESENT, + "myhost.example.com.", Option6ClientFqdn::FULL, + "myhost.example.com.", Option6ClientFqdn::FULL, + } + }; - // replace-client-name is true, client passes in a full fqdn - // response domain should be empty/partial. - request.reset(new Option6ClientFqdn(0, "myhost.example.com.", - Option6ClientFqdn::FULL)); - response.reset(new Option6ClientFqdn(*request)); - mgr.adjustDomainName(*request, *response); - EXPECT_EQ("", response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType()); + for (auto scenario : scenarios) { + SCOPED_TRACE(scenario.description_); + { + ddns_params.replace_client_name_mode_ = scenario.mode_; + Option6ClientFqdn request(0, scenario.client_name_, + scenario.client_name_type_); + + Option6ClientFqdn response(request); + mgr.adjustDomainName(request, response, ddns_params); + EXPECT_EQ(scenario.expected_name_, response.getDomainName()); + EXPECT_EQ(scenario.expected_name_type_, response.getDomainNameType()); + } + } } /// @brief Verifies the adustFqdnFlags template with Option6ClientFqdn objects. @@ -1074,19 +1046,14 @@ TEST(D2ClientMgr, adjustFqdnFlagsV6) { Option6ClientFqdnPtr request; Option6ClientFqdnPtr response; - // Create enabled configuration and override-no-update on. - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - true, false, D2ClientConfig::RCM_NEVER, - "pre-fix", "suf-fix", "", ""))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_TRUE(mgr.ddnsEnabled()); - ASSERT_TRUE(cfg->getOverrideNoUpdate()); - ASSERT_FALSE(cfg->getOverrideClientUpdate()); + // Create enabled configuration with override-no-update true. + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = true; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = ""; + ddns_params.qualifying_suffix_ = ""; // client S=0 N=0 means client wants to do forward update. // server S should be 0 (server is not doing forward updates) @@ -1096,7 +1063,7 @@ TEST(D2ClientMgr, adjustFqdnFlagsV6) { response.reset(new Option6ClientFqdn(*request)); response->resetFlags(); - mgr.adjustFqdnFlags(*request, *response); + mgr.adjustFqdnFlags(*request, *response, ddns_params); EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_S)); EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_N)); EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_O)); @@ -1110,7 +1077,7 @@ TEST(D2ClientMgr, adjustFqdnFlagsV6) { response.reset(new Option6ClientFqdn(*request)); response->resetFlags(); - mgr.adjustFqdnFlags(*request, *response); + mgr.adjustFqdnFlags(*request, *response, ddns_params); EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_S)); EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_N)); EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_O)); @@ -1124,12 +1091,13 @@ TEST(D2ClientMgr, adjustFqdnFlagsV6) { response.reset(new Option6ClientFqdn(*request)); response->resetFlags(); - mgr.adjustFqdnFlags(*request, *response); + mgr.adjustFqdnFlags(*request, *response, ddns_params); EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_S)); EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_N)); EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_O)); } + /// @brief Verified the getUpdateDirections template method with /// Option6ClientFqdn objects. TEST(D2ClientMgr, updateDirectionsV6) { @@ -1167,18 +1135,18 @@ TEST(D2ClientMgr, updateDirectionsV6) { TEST(D2ClientMgr, sanitizeFqdnV4) { D2ClientMgr mgr; - // Create enabled configuration. - // replace-client-name is false, client passes in empty fqdn - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "[^A-Za-z0-9-]", "x"))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_EQ(D2ClientConfig::RCM_NEVER, cfg->getReplaceClientNameMode()); + // Create enabled configuration with override-no-update true. + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = "prefix"; + ddns_params.qualifying_suffix_ = "suffix.com"; + + // Create and assign the sanitizer. + ASSERT_NO_THROW(ddns_params.hostname_sanitizer_.reset(new + isc::util::str::StringSanitizer("[^A-Za-z0-9-]", "x"))); struct Scenario { std::string description_; @@ -1226,19 +1194,16 @@ TEST(D2ClientMgr, sanitizeFqdnV4) { } }; - Option4ClientFqdnPtr request; - Option4ClientFqdnPtr response; - for (auto scenario = scenarios.begin(); scenario != scenarios.end(); ++scenario) { - SCOPED_TRACE((*scenario).description_); + for (auto scenario : scenarios) { + SCOPED_TRACE(scenario.description_); { - request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(), - (*scenario).client_name_, - (*scenario).name_type_)); - - response.reset(new Option4ClientFqdn(*request)); - mgr.adjustDomainName(*request, *response); - EXPECT_EQ((*scenario).expected_name_, response->getDomainName()); - EXPECT_EQ(Option4ClientFqdn::FULL, response->getDomainNameType()); + Option4ClientFqdn request(0, Option4ClientFqdn::RCODE_CLIENT(), + scenario.client_name_, scenario.name_type_); + Option4ClientFqdn response(request); + + mgr.adjustDomainName(request, response, ddns_params); + EXPECT_EQ(scenario.expected_name_, response.getDomainName()); + EXPECT_EQ(Option4ClientFqdn::FULL, response.getDomainNameType()); } } } @@ -1251,18 +1216,18 @@ TEST(D2ClientMgr, sanitizeFqdnV4) { TEST(D2ClientMgr, sanitizeFqdnV6) { D2ClientMgr mgr; - // Create enabled configuration. - // replace-client-name is false, client passes in empty fqdn - D2ClientConfigPtr cfg; - ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true, - isc::asiolink::IOAddress("127.0.0.1"), 477, - isc::asiolink::IOAddress("127.0.0.1"), 478, - 1024, - dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON, - false, false, D2ClientConfig::RCM_NEVER, - "prefix", "suffix.com", "[^A-Za-z0-9-]", "x"))); - ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg)); - ASSERT_EQ(D2ClientConfig::RCM_NEVER, cfg->getReplaceClientNameMode()); + // Create enabled configuration with override-no-update true. + DdnsParams ddns_params; + ddns_params.enable_updates_ = true; + ddns_params.override_no_update_ = false; + ddns_params.override_client_update_ = false; + ddns_params.replace_client_name_mode_ = D2ClientConfig::RCM_NEVER; + ddns_params.generated_prefix_ = "prefix"; + ddns_params.qualifying_suffix_ = "suffix.com"; + + // Create and assign the sanitizer. + ASSERT_NO_THROW(ddns_params.hostname_sanitizer_.reset(new + isc::util::str::StringSanitizer("[^A-Za-z0-9-]", "x"))); struct Scenario { std::string description_; @@ -1310,18 +1275,16 @@ TEST(D2ClientMgr, sanitizeFqdnV6) { } }; - Option6ClientFqdnPtr request; Option6ClientFqdnPtr response; - for (auto scenario = scenarios.begin(); scenario != scenarios.end(); ++scenario) { - SCOPED_TRACE((*scenario).description_); + for (auto scenario : scenarios) { + SCOPED_TRACE(scenario.description_); { - request.reset(new Option6ClientFqdn(0, (*scenario).client_name_, - (*scenario).name_type_)); + Option6ClientFqdn request(0, scenario.client_name_, scenario.name_type_); + Option6ClientFqdn response(request); - response.reset(new Option6ClientFqdn(*request)); - mgr.adjustDomainName(*request, *response); - EXPECT_EQ((*scenario).expected_name_, response->getDomainName()); - EXPECT_EQ(Option6ClientFqdn::FULL, response->getDomainNameType()); + mgr.adjustDomainName(request, response, ddns_params); + EXPECT_EQ(scenario.expected_name_, response.getDomainName()); + EXPECT_EQ(Option6ClientFqdn::FULL, response.getDomainNameType()); } } }